Merge branch 'test' of ../kivitendo-erp_20220811
authorMichael Wagner <michael@wagnertech.de>
Fri, 12 Aug 2022 11:56:13 +0000 (13:56 +0200)
committerMichael Wagner <michael@wagnertech.de>
Fri, 12 Aug 2022 11:56:13 +0000 (13:56 +0200)
504 files changed:
SL/AM.pm
SL/AP.pm
SL/AR.pm
SL/BackgroundJob/CreateOrUpdateFileFullTexts.pm [new file with mode: 0644]
SL/BackgroundJob/CreatePeriodicInvoices.pm
SL/BackgroundJob/MassRecordCreationAndPrinting.pm
SL/BackgroundJob/SelfTest/Transactions.pm
SL/CT.pm
SL/CVar.pm
SL/Clipboard/Base.pm [deleted file]
SL/Clipboard/RequirementSpecItem.pm [deleted file]
SL/Clipboard/RequirementSpecPicture.pm [deleted file]
SL/Clipboard/RequirementSpecTextBlock.pm [deleted file]
SL/Common.pm
SL/Controller/Admin.pm
SL/Controller/BankTransaction.pm
SL/Controller/Base.pm
SL/Controller/ClientConfig.pm
SL/Controller/CsvImport.pm
SL/Controller/CsvImport/AdditionalBillingAddress.pm [new file with mode: 0644]
SL/Controller/CsvImport/Base.pm
SL/Controller/CsvImport/BaseMulti.pm
SL/Controller/CsvImport/Clipboard/Base.pm [new file with mode: 0644]
SL/Controller/CsvImport/Clipboard/RequirementSpecItem.pm [new file with mode: 0644]
SL/Controller/CsvImport/Clipboard/RequirementSpecPicture.pm [new file with mode: 0644]
SL/Controller/CsvImport/Clipboard/RequirementSpecTextBlock.pm [new file with mode: 0644]
SL/Controller/CsvImport/DeliveryOrder.pm
SL/Controller/CsvImport/Helper/Consistency.pm
SL/Controller/CsvImport/Inventory.pm
SL/Controller/CustomVariableConfig.pm
SL/Controller/CustomerVendor.pm
SL/Controller/DeliveryOrder.pm [new file with mode: 0644]
SL/Controller/DeliveryOrder/TypeData.pm [new file with mode: 0644]
SL/Controller/DeliveryPlan.pm
SL/Controller/DeliveryValueReport.pm
SL/Controller/File.pm
SL/Controller/ImageUpload.pm
SL/Controller/Inventory.pm
SL/Controller/Letter.pm
SL/Controller/MassInvoiceCreatePrint.pm
SL/Controller/Mebil.pm
SL/Controller/Order.pm
SL/Controller/Part.pm
SL/Controller/PayPostingImport.pm
SL/Controller/PriceSource.pm
SL/Controller/Project.pm
SL/Controller/RecordLinks.pm
SL/Controller/RequirementSpec.pm
SL/Controller/ShopOrder.pm
SL/Controller/ShopPart.pm
SL/Controller/SimpleSystemSetting.pm
SL/Controller/TopQuickSearch.pm
SL/Controller/TopQuickSearch/PhoneNumber.pm [new file with mode: 0644]
SL/Controller/TopQuickSearch/PurchaseDeliveryOrder.pm
SL/Controller/TopQuickSearch/PurchaseOrder.pm
SL/Controller/TopQuickSearch/RequestForQuotation.pm
SL/Controller/TopQuickSearch/SalesDeliveryOrder.pm
SL/Controller/TopQuickSearch/SalesOrder.pm
SL/Controller/TopQuickSearch/SalesQuotation.pm
SL/DATEV.pm
SL/DB/AdditionalBillingAddress.pm [new file with mode: 0644]
SL/DB/ApGl.pm [new file with mode: 0644]
SL/DB/BankTransaction.pm
SL/DB/CustomVariable.pm
SL/DB/CustomVariableConfig.pm
SL/DB/Customer.pm
SL/DB/DeliveryOrder.pm
SL/DB/DeliveryOrder/TypeData.pm [new file with mode: 0644]
SL/DB/DeliveryOrderItem.pm
SL/DB/DeliveryOrderItemsStock.pm
SL/DB/Employee.pm
SL/DB/File.pm
SL/DB/FileFullText.pm [new file with mode: 0644]
SL/DB/GLTransaction.pm
SL/DB/Helper/ALL.pm
SL/DB/Helper/FlattenToForm.pm
SL/DB/Helper/LinkedRecords.pm
SL/DB/Helper/Mappings.pm
SL/DB/Helper/Payment.pm
SL/DB/Helper/SalesPurchaseInvoice.pm [new file with mode: 0644]
SL/DB/Helper/TransNumberGenerator.pm
SL/DB/Inventory.pm
SL/DB/Invoice.pm
SL/DB/Manager/AdditionalBillingAddress.pm [new file with mode: 0644]
SL/DB/Manager/ApGl.pm [new file with mode: 0644]
SL/DB/Manager/DeliveryOrder.pm
SL/DB/Manager/FileFullText.pm [new file with mode: 0644]
SL/DB/MetaSetup/AdditionalBillingAddress.pm [new file with mode: 0644]
SL/DB/MetaSetup/ApGl.pm [new file with mode: 0644]
SL/DB/MetaSetup/BankAccount.pm
SL/DB/MetaSetup/Default.pm
SL/DB/MetaSetup/DeliveryOrder.pm
SL/DB/MetaSetup/File.pm
SL/DB/MetaSetup/FileFullText.pm [new file with mode: 0644]
SL/DB/MetaSetup/GLTransaction.pm
SL/DB/MetaSetup/Invoice.pm
SL/DB/MetaSetup/InvoiceItem.pm
SL/DB/MetaSetup/Language.pm
SL/DB/MetaSetup/Order.pm
SL/DB/MetaSetup/OrderItem.pm
SL/DB/MetaSetup/RecordTemplate.pm
SL/DB/MetaSetup/Shop.pm
SL/DB/MetaSetup/ShopOrder.pm
SL/DB/MetaSetup/ShopOrderItem.pm
SL/DB/MetaSetup/Tax.pm
SL/DB/Order.pm
SL/DB/Part.pm
SL/DB/PaymentTerm.pm
SL/DB/Pricegroup.pm
SL/DB/PurchaseInvoice.pm
SL/DB/Shop.pm
SL/DB/ShopOrder.pm
SL/DB/ShopPart.pm
SL/DB/VC.pm
SL/DN.pm
SL/DO.pm
SL/Dev/Record.pm
SL/FU.pm
SL/File.pm
SL/File/Backend/Filesystem.pm
SL/File/Backend/Webdav.pm
SL/Form.pm
SL/GL.pm
SL/HTML/Util.pm
SL/Helper/File.pm
SL/Helper/Inventory.pm
SL/Helper/Number.pm
SL/Helper/PrintOptions.pm
SL/Helper/QrBill.pm [new file with mode: 0644]
SL/Helper/ShippedQty.pm
SL/Helper/UNECERecommendation20.pm
SL/Helper/UserPreferences/DisplayPreferences.pm [new file with mode: 0644]
SL/IC.pm
SL/IS.pm
SL/InstallationCheck.pm
SL/Mailer.pm
SL/OE.pm
SL/Presenter/DeliveryOrder.pm
SL/Presenter/Record.pm
SL/Presenter/Tag.pm
SL/Presenter/Text.pm
SL/RP.pm
SL/RecordLinks.pm
SL/SEPA/XML.pm
SL/ShopConnector/ALL.pm
SL/ShopConnector/Base.pm
SL/ShopConnector/Shopware.pm
SL/ShopConnector/Shopware6.pm [new file with mode: 0644]
SL/Template.pm
SL/Template/OpenDocument.pm
SL/Template/Plugin/KiviLatex.pm
SL/Template/Plugin/L.pm
SL/Template/Plugin/LxERP.pm
SL/TransNumber.pm
SL/WH.pm
SL/Webdav.pm
SL/Webdav/File.pm
SL/Webdav/Object.pm
SL/mebil/ERiC.pm [new file with mode: 0644]
VERSION
bin/mozilla/am.pl
bin/mozilla/ap.pl
bin/mozilla/ar.pl
bin/mozilla/common.pl
bin/mozilla/ct.pl
bin/mozilla/dn.pl
bin/mozilla/do.pl
bin/mozilla/fu.pl
bin/mozilla/generictranslations.pl
bin/mozilla/gl.pl
bin/mozilla/ic.pl
bin/mozilla/io.pl
bin/mozilla/ir.pl
bin/mozilla/is.pl
bin/mozilla/login.pl
bin/mozilla/oe.pl
bin/mozilla/rp.pl
bin/mozilla/wh.pl
build/kivitendo-mebil.co [new file with mode: 0755]
build/kivitendo-steckbrief.co [new file with mode: 0755]
build/kivitendo.co [new file with mode: 0755]
build/start-build [new file with mode: 0755]
debian/mkivitendo.changelog
debian/mkivitendo.control
debian/mkivitendo.cp
debian/mkivitendo.postinst [new file with mode: 0755]
debian/mkivitendo.prepare
doc/Steckbrief.tex [new file with mode: 0644]
doc/UPGRADE
doc/changelog
doc/dokumentation.xml
doc/html/ch01.html
doc/html/ch02.html
doc/html/ch02s02.html
doc/html/ch02s03.html
doc/html/ch02s04.html
doc/html/ch02s05.html
doc/html/ch02s06.html
doc/html/ch02s07.html
doc/html/ch02s08.html
doc/html/ch02s09.html
doc/html/ch02s10.html
doc/html/ch02s11.html
doc/html/ch02s12.html
doc/html/ch02s13.html
doc/html/ch02s14.html
doc/html/ch02s15.html
doc/html/ch02s16.html
doc/html/ch02s17.html
doc/html/ch02s18.html
doc/html/ch02s19.html
doc/html/ch02s20.html
doc/html/ch02s21.html
doc/html/ch03.html
doc/html/ch03s02.html
doc/html/ch03s03.html
doc/html/ch03s04.html
doc/html/ch03s05.html
doc/html/ch03s06.html
doc/html/ch03s07.html
doc/html/ch03s08.html
doc/html/ch03s09.html
doc/html/ch03s10.html
doc/html/ch04.html
doc/html/ch04s02.html
doc/html/ch04s03.html
doc/html/ch04s04.html
doc/html/ch04s05.html
doc/html/ch04s06.html
doc/html/ch04s07.html
doc/html/ch04s08.html
doc/html/index.html
doc/html/system/docbook-xsl/images/tip.png [new file with mode: 0644]
doc/kivitendo-Dokumentation.pdf
doc/release_management.txt
image/Bildschirmfoto-kivitendo-steigmann-3.3.0-MozillaFirefox.png [new file with mode: 0644]
image/CH-Kreuz_7mm.png [new file with mode: 0644]
image/kivitendo_corona.png [deleted file]
image/kivitendo_mir.png [new file with mode: 0644]
js/ckeditor/build-config.js
js/ckeditor/ckeditor.js
js/ckeditor/config.js
js/ckeditor/lang/de.js
js/ckeditor/lang/en.js
js/ckeditor/plugins/codemirror/css/codemirror.min.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/beautify.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/codemirror.addons.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/codemirror.addons.search.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/codemirror.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/codemirror.mode.bbcode.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/codemirror.mode.bbcodemixed.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/codemirror.mode.htmlmixed.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/codemirror.mode.javascript.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/codemirror.mode.php.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/js/codemirror.mode.twig.min.js [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/3024-day.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/3024-night.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/abcdef.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/ambiance-mobile.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/ambiance.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/base16-dark.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/base16-light.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/bespin.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/blackboard.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/cobalt.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/colorforth.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/dracula.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/duotone-dark.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/duotone-light.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/eclipse.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/elegant.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/erlang-dark.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/hopscotch.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/icecoder.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/isotope.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/lesser-dark.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/liquibyte.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/material.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/mbo.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/mdn-like.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/midnight.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/monokai.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/neat.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/neo.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/night.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/panda-syntax.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/paraiso-dark.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/paraiso-light.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/pastel-on-dark.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/railscasts.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/rubyblue.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/seti.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/solarized.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/the-matrix.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/tomorrow-night-bright.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/tomorrow-night-eighties.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/ttcn.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/twilight.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/vibrant-ink.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/xq-dark.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/xq-light.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/yeti.css [new file with mode: 0644]
js/ckeditor/plugins/codemirror/theme/zenburn.css [new file with mode: 0644]
js/ckeditor/plugins/icons.png
js/ckeditor/plugins/icons_hidpi.png
js/ckeditor/plugins/inline_resize/plugin.js
js/ckeditor/plugins/sourcedialog/dialogs/sourcedialog.js [new file with mode: 0644]
js/ckeditor/samples/old/index.html
js/ckeditor/samples/old/sourcedialog/sourcedialog.html [new file with mode: 0644]
js/ckeditor/skins/moono-lisa/editor.css
js/ckeditor/skins/moono-lisa/editor_gecko.css
js/ckeditor/skins/moono-lisa/editor_ie.css
js/ckeditor/skins/moono-lisa/editor_ie8.css
js/ckeditor/skins/moono-lisa/editor_iequirks.css
js/ckeditor/skins/moono-lisa/icons.png
js/ckeditor/skins/moono-lisa/icons_hidpi.png
js/kivi.BankTransaction.js
js/kivi.CustomerVendor.js
js/kivi.DeliveryOrder.js [new file with mode: 0644]
js/kivi.File.js
js/kivi.Order.js
js/kivi.QuickSearch.js
js/kivi.SalesPurchase.js
js/kivi.ShopPart.js
js/kivi.Validator.js
js/kivi.js
js/locale/de.js
js/locale/en.js
locale/de/all
locale/de/special_chars
locale/en/all
locale/en/special_chars
menus/user/00-erp.yaml
menus/user/20-invoice-for-advance-payment.yaml [new file with mode: 0644]
scripts/console
sql/Pg-upgrade2-auth/convert_columns_to_html_for_sending_html_emails.pl [new file with mode: 0644]
sql/Pg-upgrade2-auth/release_3_6_0.sql [new file with mode: 0644]
sql/Pg-upgrade2-auth/release_3_6_1.sql [new file with mode: 0644]
sql/Pg-upgrade2-auth/rights_view_docs.sql [new file with mode: 0644]
sql/Pg-upgrade2/add_gl_transaction_description.sql [new file with mode: 0644]
sql/Pg-upgrade2/add_record_templates_transaction_description.sql [new file with mode: 0644]
sql/Pg-upgrade2/ap_gl.sql [new file with mode: 0644]
sql/Pg-upgrade2/ar_add_qrbill_without_amount.sql [new file with mode: 0644]
sql/Pg-upgrade2/bank_account_informations_for_swiss_qrbill.sql [new file with mode: 0644]
sql/Pg-upgrade2/clean_tax_18_19.pl [new file with mode: 0644]
sql/Pg-upgrade2/convert_columns_to_html_for_sending_html_emails.pl [new file with mode: 0644]
sql/Pg-upgrade2/convert_columns_to_html_for_sending_html_emails2.pl [new file with mode: 0644]
sql/Pg-upgrade2/convert_real_qty.sql [new file with mode: 0644]
sql/Pg-upgrade2/custom_variables_convert_width_height_to_pixels.pl [new file with mode: 0644]
sql/Pg-upgrade2/customer_additional_billing_addresses.sql [new file with mode: 0644]
sql/Pg-upgrade2/customer_remove_empty_additional_billing_addresses.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_advance_payment_clearing_chart_id.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_advance_payment_transfer_charts.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_create_qrbill_data.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_invoice_prevent_browser_back.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_invoice_warn_no_delivery_order.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_order_controller.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_order_warn_no_cusordnumber.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_partsgroup_required.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_print_interpolate_variables_in_positions.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_qrbill_variants.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_sales_purchase_record_numbers_changeable.sql [new file with mode: 0644]
sql/Pg-upgrade2/defaults_view_record_links.sql [new file with mode: 0644]
sql/Pg-upgrade2/delete_wrong_charts_for_taxkeys.pl [new file with mode: 0644]
sql/Pg-upgrade2/delete_wrong_charts_for_taxkeys_04.pl [new file with mode: 0644]
sql/Pg-upgrade2/deliveryorder_transnumbers.sql [new file with mode: 0644]
sql/Pg-upgrade2/deliveryorder_type.sql [new file with mode: 0644]
sql/Pg-upgrade2/file_full_texts.sql [new file with mode: 0644]
sql/Pg-upgrade2/file_storage_partial_invoices.sql [new file with mode: 0644]
sql/Pg-upgrade2/files_add_variant.sql [new file with mode: 0644]
sql/Pg-upgrade2/full_texts_background_job.sql [new file with mode: 0644]
sql/Pg-upgrade2/language_obsolete.sql [new file with mode: 0644]
sql/Pg-upgrade2/link_requirement_spec_to_orders_created_from_quotations_created_from_requirement_spec.sql [new file with mode: 0644]
sql/Pg-upgrade2/new_chart_1593_1495.sql [new file with mode: 0644]
sql/Pg-upgrade2/new_chart_3260_1711.sql [new file with mode: 0644]
sql/Pg-upgrade2/new_chart_3272_1718.sql [new file with mode: 0644]
sql/Pg-upgrade2/record_links_remove_to_quotation.pl [new file with mode: 0644]
sql/Pg-upgrade2/release_3_6_0.sql [new file with mode: 0644]
sql/Pg-upgrade2/release_3_6_1.sql [new file with mode: 0644]
sql/Pg-upgrade2/remove_oids.sql [new file with mode: 0644]
sql/Pg-upgrade2/shop_orders_update_4.sql [new file with mode: 0644]
sql/Pg-upgrade2/shops_5.sql [new file with mode: 0644]
sql/Pg-upgrade2/shops_6.sql [new file with mode: 0644]
sql/Pg-upgrade2/tax_reverse_charge.sql [new file with mode: 0644]
sql/Pg-upgrade2/tax_reverse_charge_key_18.sql [new file with mode: 0644]
sql/Pg-upgrade2/tax_reverse_charge_key_19.sql [new file with mode: 0644]
sql/mebil.sql [new file with mode: 0644]
t/bank/bank_transactions.t
t/controllers/csvimport/delivery_orders.t [new file with mode: 0644]
t/controllers/csvimport/inventory.t [new file with mode: 0644]
t/db/delivery_order.t [new file with mode: 0644]
t/db_helper/convert_invoice.t
t/db_helper/payment.t
t/db_helper/record_links.t
t/pay_posting_import/datev_import.t
t/run.sh
t/tax/tax.t
templates/print/marei/Readme.md
templates/print/marei/bin_list.tex
templates/print/marei/check.tex
templates/print/marei/credit_note.tex
templates/print/marei/deutsch.tex
templates/print/marei/english.tex
templates/print/marei/final_invoice.tex [new symlink]
templates/print/marei/firma/chf_account.tex
templates/print/marei/firma/default_account.tex [deleted file]
templates/print/marei/firma/euro_account.tex
templates/print/marei/ic_supply.tex
templates/print/marei/ic_supply_EN.tex
templates/print/marei/insettings.tex
templates/print/marei/invoice.tex
templates/print/marei/invoice_copy.tex [new symlink]
templates/print/marei/invoice_for_advance_payment.tex [new symlink]
templates/print/marei/kiviletter.sty
templates/print/marei/kivitendo.sty
templates/print/marei/letter.tex
templates/print/marei/pick_list.tex
templates/print/marei/proforma.tex
templates/print/marei/purchase_delivery_order.tex
templates/print/marei/purchase_order.tex
templates/print/marei/receipt.tex
templates/print/marei/request_quotation.tex
templates/print/marei/requirement_spec.tex
templates/print/marei/sales_delivery_order.tex
templates/print/marei/sales_order.tex
templates/print/marei/sales_quotation.tex
templates/print/marei/statement.tex
templates/print/marei/supplier_delivery_order.tex [new symlink]
templates/print/marei/zahlungserinnerung.tex
templates/print/marei/zahlungserinnerung_invoice.tex
templates/print/rev-odt/invoice_qr.odt [new file with mode: 0644]
templates/webpages/admin/edit_user.html
templates/webpages/am/config.html
templates/webpages/amcvar/render_inputs.html
templates/webpages/amcvar/render_inputs_block.html
templates/webpages/ap/form_header.html
templates/webpages/ap/search.html
templates/webpages/ar/form_header.html
templates/webpages/ar/search.html
templates/webpages/bank_transactions/create_invoice.html
templates/webpages/ca/list.html
templates/webpages/client_config/_default_accounts.html
templates/webpages/client_config/_features.html
templates/webpages/client_config/_miscellaneous.html
templates/webpages/client_config/_posting_configuration.html
templates/webpages/client_config/_record_links.html [new file with mode: 0644]
templates/webpages/client_config/form.html
templates/webpages/common/_send_email_dialog.html
templates/webpages/common/render_cvar_input.html
templates/webpages/common/show_vc_details.html
templates/webpages/csv_import/form.html
templates/webpages/ct/search.html
templates/webpages/custom_variable_config/form.html
templates/webpages/customer_vendor/form.html
templates/webpages/customer_vendor/tabs/additional_billing_addresses.html [new file with mode: 0644]
templates/webpages/customer_vendor/tabs/billing.html
templates/webpages/customer_vendor/tabs/shipto.html
templates/webpages/datev/export.html
templates/webpages/datev/export_bewegungsdaten.html
templates/webpages/datev/net_gross_difference.html
templates/webpages/delivery_order/form.html [new file with mode: 0644]
templates/webpages/delivery_order/stock_dialog.html [new file with mode: 0644]
templates/webpages/delivery_order/tabs/_business_info_row.html [new file with mode: 0644]
templates/webpages/delivery_order/tabs/_item_input.html [new file with mode: 0644]
templates/webpages/delivery_order/tabs/_row.html [new file with mode: 0644]
templates/webpages/delivery_order/tabs/_second_row.html [new file with mode: 0644]
templates/webpages/delivery_order/tabs/basic_data.html [new file with mode: 0644]
templates/webpages/delivery_value_report/_filter.html
templates/webpages/do/form_header.html
templates/webpages/dunning/set_email.html
templates/webpages/dunning/show_invoices.html
templates/webpages/email_journal/show.html
templates/webpages/file/list.html
templates/webpages/fu/add_edit.html
templates/webpages/generic/set_longdescription.html
templates/webpages/generictranslations/edit_email_strings.html
templates/webpages/gl/form_header.html
templates/webpages/gl/search.html
templates/webpages/ir/_payments.html
templates/webpages/is/_payments.html
templates/webpages/is/form_footer.html
templates/webpages/is/form_header.html
templates/webpages/oe/edit_periodic_invoices_config.html
templates/webpages/oe/form_header.html
templates/webpages/oe/search.html
templates/webpages/order/form.html
templates/webpages/order/tabs/_item_input.html
templates/webpages/order/tabs/basic_data.html
templates/webpages/order/tabs/phone_notes.html [new file with mode: 0644]
templates/webpages/part/_basic_data.html
templates/webpages/part/_shop.html
templates/webpages/project/form.html
templates/webpages/record_links/add_filter.html
templates/webpages/requirement_spec/_show_basic_settings.html
templates/webpages/shop_order/show.html
templates/webpages/shop_part/categories.html
templates/webpages/shop_part/edit.html
templates/webpages/shops/form.html
templates/webpages/shops/test_shop_connection.html
templates/webpages/simple_system_setting/_bank_account_form.html
templates/webpages/simple_system_setting/_language_form.html
templates/webpages/simple_system_setting/_pricegroup_form.html
templates/webpages/wh/journal_filter.html
templates/webpages/wh/report_filter.html

index 57e6b44..2d8ed4c 100644 (file)
--- a/SL/AM.pm
+++ b/SL/AM.pm
@@ -52,6 +52,7 @@ use SL::DB::Part;
 use SL::DB::Vendor;
 use SL::DB;
 use SL::GenericTranslations;
+use SL::Helper::UserPreferences::DisplayPreferences;
 use SL::Helper::UserPreferences::PositionsScrollbar;
 use SL::Helper::UserPreferences::PartPickerSearch;
 use SL::Helper::UserPreferences::TimeRecording;
@@ -551,12 +552,16 @@ sub time_recording_use_duration {
   SL::Helper::UserPreferences::TimeRecording->new()->get_use_duration();
 }
 
+sub longdescription_dialog_size_percentage {
+  SL::Helper::UserPreferences::DisplayPreferences->new()->get_longdescription_dialog_size_percentage();
+}
+
 sub save_preferences {
   $main::lxdebug->enter_sub();
 
   my ($self, $form) = @_;
 
-  my $employee = SL::DB::Manager::Employee->find_by(login => $::myconfig{login});
+  my $employee = SL::DB::Manager::Employee->current;
   $employee->update_attributes(name => $form->{name});
 
   my $user = SL::DB::Manager::AuthUser->find_by(login => $::myconfig{login});
@@ -591,6 +596,9 @@ sub save_preferences {
   if (exists $form->{time_recording_use_duration}) {
     SL::Helper::UserPreferences::TimeRecording->new()->store_use_duration($form->{time_recording_use_duration})
   }
+  if (exists $form->{longdescription_dialog_size_percentage}) {
+    SL::Helper::UserPreferences::DisplayPreferences->new()->store_longdescription_dialog_size_percentage($form->{longdescription_dialog_size_percentage})
+  }
 
   $main::lxdebug->leave_sub();
 
@@ -1249,6 +1257,8 @@ sub save_warehouse {
 
   my ($self, $myconfig, $form) = @_;
 
+  croak('Need at least one new bin') unless $form->{number_of_new_bins} > 0;
+
   SL::DB->client->with_transaction(sub {
     my $dbh = SL::DB->client->dbh;
 
index 601083b..d399b7c 100644 (file)
--- a/SL/AP.pm
+++ b/SL/AP.pm
@@ -39,6 +39,7 @@ use SL::DATEV qw(:CONSTANTS);
 use SL::DBUtils;
 use SL::IO;
 use SL::MoreCommon;
+use SL::DB::ApGl;
 use SL::DB::Default;
 use SL::DB::Draft;
 use SL::DB::Order;
@@ -141,7 +142,7 @@ sub _post_transaction {
                 transdate = ?, ordnumber = ?, vendor_id = ?, taxincluded = ?,
                 amount = ?, duedate = ?, deliverydate = ?, tax_point = ?, paid = ?, netamount = ?,
                 currency_id = (SELECT id FROM currencies WHERE name = ?), notes = ?, department_id = ?, storno = ?, storno_id = ?,
-                globalproject_id = ?, direct_debit = ?, payment_id = ?
+                globalproject_id = ?, direct_debit = ?, payment_id = ?, transaction_description = ?
                WHERE id = ?|;
     @values = ($form->{invnumber}, conv_date($form->{transdate}),
                   $form->{ordnumber}, conv_i($form->{vendor_id}),
@@ -152,7 +153,7 @@ sub _post_transaction {
                   conv_i($form->{department_id}), $form->{storno},
                   $form->{storno_id}, conv_i($form->{globalproject_id}),
                   $form->{direct_debit} ? 't' : 'f',
-                  conv_i($form->{payment_id}),
+                  conv_i($form->{payment_id}), $form->{transaction_description},
                   $form->{id});
     do_query($form, $dbh, $query, @values);
 
@@ -406,6 +407,8 @@ sub _post_transaction {
     SL::DB::Manager::Draft->delete_all(where => [ id => delete($form->{draft_id}) ]);
   }
 
+  # hook for taxkey 94
+  $self->_reverse_charge($myconfig, $form);
   # safety check datev export
   if ($::instance_conf->get_datev_check_on_ap_transaction) {
     my $datev = SL::DATEV->new(
@@ -422,12 +425,86 @@ sub _post_transaction {
   return 1;
 }
 
+sub _reverse_charge {
+  my ($self, $myconfig, $form) = @_;
+
+  # delete previous bookings, if they exists (repost)
+  my $ap_gl = SL::DB::Manager::ApGl->get_first(where => [ ap_id => $form->{id} ]);
+  my $gl_id = ref $ap_gl eq 'SL::DB::ApGl' ? $ap_gl->gl_id : undef;
+
+  SL::DB::Manager::GLTransaction->delete_all(where => [ id    => $gl_id ])       if $gl_id;
+  SL::DB::Manager::ApGl->         delete_all(where => [ ap_id => $form->{id} ])  if $gl_id;
+  SL::DB::Manager::RecordLink->   delete_all(where => [ from_table => 'ap', to_table => 'gl', from_id => $form->{id} ]);
+
+  my ($i, $current_transaction);
+
+  for $i (1 .. $form->{rowcount}) {
+
+    my $tax = SL::DB::Manager::Tax->get_first( where => [id => $form->{"tax_id_$i"}, '!reverse_charge_chart_id' => undef ]);
+    next unless ref $tax eq 'SL::DB::Tax';
+
+    # gl booking
+    my ($credit, $debit);
+    $credit   = SL::DB::Manager::Chart->find_by(id => $tax->chart_id);
+    $debit    = SL::DB::Manager::Chart->find_by(id => $tax->reverse_charge_chart_id);
+
+    croak("No such Chart ID" . $tax->chart_id)          unless ref $credit eq 'SL::DB::Chart';
+    croak("No such Chart ID" . $tax->reverse_chart_id)  unless ref $debit  eq 'SL::DB::Chart';
+
+    my ($tmpnetamount, $tmptaxamount) = $form->calculate_tax($form->{"amount_$i"}, $tax->rate, $form->{taxincluded}, 2);
+    $current_transaction = SL::DB::GLTransaction->new(
+          employee_id    => $form->{employee_id},
+          transdate      => $form->{transdate},
+          description    => $form->{notes} || $form->{invnumber},
+          reference      => $form->{invnumber},
+          department_id  => $form->{department_id} ? $form->{department_id} : undef,
+          imported       => 0, # not imported
+          taxincluded    => 0,
+        )->add_chart_booking(
+          chart  => $tmptaxamount > 0 ? $debit : $credit,
+          debit  => abs($tmptaxamount),
+          source => "Reverse Charge for " . $form->{invnumber},
+          tax_id => 0,
+        )->add_chart_booking(
+          chart  => $tmptaxamount > 0 ? $credit : $debit,
+          credit => abs($tmptaxamount),
+          source => "Reverse Charge for " . $form->{invnumber},
+          tax_id => 0,
+      )->post;
+    # add a stable link from ap to gl
+    my %props_gl = (
+        ap_id => $form->{id},
+        gl_id => $current_transaction->id,
+      );
+    SL::DB::ApGl->new(%props_gl)->save;
+    # Record a record link from ap to gl
+    my %props_rl = (
+        from_table => 'ap',
+        from_id    => $form->{id},
+        to_table   => 'gl',
+        to_id      => $current_transaction->id,
+      );
+    SL::DB::RecordLink->new(%props_rl)->save;
+  }
+}
+
 sub delete_transaction {
   $main::lxdebug->enter_sub();
 
   my ($self, $myconfig, $form) = @_;
 
   SL::DB->client->with_transaction(sub {
+
+    # if tax 94 reverse charge, clear all GL bookings and links
+    my $ap_gl = SL::DB::Manager::ApGl->get_first(where => [ ap_id => $form->{id} ]);
+    my $gl_id = ref $ap_gl eq 'SL::DB::ApGl' ? $ap_gl->gl_id : undef;
+
+    SL::DB::Manager::GLTransaction->delete_all(where => [ id    => $gl_id ])       if $gl_id;
+    SL::DB::Manager::ApGl->         delete_all(where => [ ap_id => $form->{id} ])  if $gl_id;
+    SL::DB::Manager::RecordLink->   delete_all(where => [ from_table => 'ap', to_table => 'gl', from_id => $form->{id} ]);
+    # done gl delete for tax 94 case
+
+    # begin ap delete
     my $query = qq|DELETE FROM ap WHERE id = ?|;
     do_query($form, SL::DB->client->dbh, $query, $form->{id});
     1;
@@ -487,16 +564,16 @@ sub ap_transactions {
   # Permissions:
   # - Always return invoices & AP transactions for projects the employee has "view invoices" permissions for, no matter what the other rules say.
   # - Exclude AP transactions if no permissions for them exist.
-  # - Limit to own invoices unless may edit all invoices.
-  # - If may edit all, allow filtering by employee.
+  # - Limit to own invoices unless may edit all invoices or view invoices is allowed.
+  # - If may edit all or view invoices is allowed, allow filtering by employee.
   my (@permission_where, @permission_values);
 
-  if ($::auth->assert('vendor_invoice_edit', 1)) {
+  if ($::auth->assert('vendor_invoice_edit', 1) || $::auth->assert('purchase_invoice_view', 1)) {
     if (!$::auth->assert('show_ap_transactions', 1)) {
       push @permission_where, "NOT invoice = 'f'"; # remove ap transactions from Purchase -> Reports -> Invoices
     }
 
-    if (!$::auth->assert('purchase_all_edit', 1)) {
+    if (!$::auth->assert('purchase_all_edit', 1) && !$::auth->assert('purchase_invoice_view', 1)) {
       # only show own invoices
       push @permission_where,  "a.employee_id = ?";
       push @permission_values, SL::DB::Manager::Employee->current->id;
@@ -509,7 +586,7 @@ sub ap_transactions {
     }
   }
 
-  if (@permission_where || !$::auth->assert('vendor_invoice_edit', 1)) {
+  if (@permission_where || (!$::auth->assert('vendor_invoice_edit', 1) && !$::auth->assert('purchase_invoice_view', 1))) {
     my $permission_where_str = @permission_where ? "OR (" . join(" AND ", map { "($_)" } @permission_where) . ")" : "";
     $where .= qq|
       AND (   (a.globalproject_id IN (
@@ -541,12 +618,16 @@ sub ap_transactions {
     $where .= " AND a.ordnumber ILIKE ?";
     push(@values, like($form->{ordnumber}));
   }
+  if ($form->{taxzone_id}) {
+    $where .= " AND a.taxzone_id = ?";
+    push(@values, $form->{taxzone_id});
+  }
   if ($form->{transaction_description}) {
     $where .= " AND a.transaction_description ILIKE ?";
     push(@values, like($form->{transaction_description}));
   }
   if ($form->{notes}) {
-    $where .= " AND lower(a.notes) LIKE ?";
+    $where .= " AND a.notes ILIKE ?";
     push(@values, like($form->{notes}));
   }
   if ($form->{project_id}) {
@@ -621,7 +702,7 @@ SQL
   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
   my $sortorder = join(', ', map { "$_ $sortdir" } @a);
 
-  if (grep({ $_ eq $form->{sort} } qw(transdate id invnumber ordnumber name netamount tax amount paid datepaid due duedate notes employee transaction_description direct_debit department))) {
+  if (grep({ $_ eq $form->{sort} } qw(transdate id invnumber ordnumber name netamount tax amount paid datepaid due duedate notes employee transaction_description direct_debit department taxzone))) {
     $sortorder = $form->{sort} . " $sortdir";
   }
 
index b856f44..db8a4ac 100644 (file)
--- a/SL/AR.pm
+++ b/SL/AR.pm
@@ -138,14 +138,15 @@ sub _post_transaction {
            currency_id = (SELECT id FROM currencies WHERE name = ?),
            netamount = ?, notes = ?, department_id = ?,
            employee_id = ?, storno = ?, storno_id = ?, globalproject_id = ?,
-           direct_debit = ?
+           direct_debit = ?, transaction_description = ?
          WHERE id = ?|;
     my @values = ($form->{invnumber}, $form->{ordnumber}, conv_date($form->{transdate}), conv_i($form->{customer_id}), $form->{taxincluded} ? 't' : 'f', $form->{amount},
                   conv_date($form->{duedate}), conv_date($form->{deliverydate}), conv_date($form->{tax_point}), $form->{paid},
                   $form->{currency},
                   $form->{netamount}, $form->{notes}, conv_i($form->{department_id}),
                   conv_i($form->{employee_id}), $form->{storno} ? 't' : 'f', $form->{storno_id},
-                  conv_i($form->{globalproject_id}), $form->{direct_debit} ? 't' : 'f', conv_i($form->{id}));
+                  conv_i($form->{globalproject_id}), $form->{direct_debit} ? 't' : 'f', $form->{transaction_description},
+                  conv_i($form->{id}));
     do_query($form, $dbh, $query, @values);
 
     # add individual transactions for AR, amount and taxes
@@ -487,6 +488,7 @@ sub ar_transactions {
     qq|  a.shippingpoint, a.storno, a.storno_id, a.globalproject_id, | .
     qq|  a.marge_total, a.marge_percent, | .
     qq|  a.transaction_description, a.direct_debit, | .
+    qq|  a.type, | .
     qq|  pr.projectnumber AS globalprojectnumber, | .
     qq|  c.name, c.customernumber, c.country, c.ustid, b.description as customertype, | .
     qq|  c.id as customer_id, | .
@@ -520,16 +522,16 @@ sub ar_transactions {
   # Permissions:
   # - Always return invoices & AR transactions for projects the employee has "view invoices" permissions for, no matter what the other rules say.
   # - Exclude AR transactions if no permissions for them exist.
-  # - Limit to own invoices unless may edit all invoices.
-  # - If may edit all, allow filtering by employee/salesman.
+  # - Limit to own invoices unless may edit all invoices or view invoices is allowed.
+  # - If may edit all or view invoices is allowed, allow filtering by employee/salesman.
   my (@permission_where, @permission_values);
 
-  if ($::auth->assert('invoice_edit', 1)) {
+  if ($::auth->assert('invoice_edit', 1) || $::auth->assert('sales_invoice_view', 1)) {
     if (!$::auth->assert('show_ar_transactions', 1) ) {
       push @permission_where, "NOT invoice = 'f'";  # remove ar transactions from Sales -> Reports -> Invoices
     }
 
-    if (!$::auth->assert('sales_all_edit', 1)) {
+    if (!$::auth->assert('sales_all_edit', 1) && !$::auth->assert('sales_invoice_view', 1)) {
       # only show own invoices
       push @permission_where,  "a.employee_id = ?";
       push @permission_values, SL::DB::Manager::Employee->current->id;
@@ -546,7 +548,7 @@ sub ar_transactions {
     }
   }
 
-  if (@permission_where || !$::auth->assert('invoice_edit', 1)) {
+  if (@permission_where || (!$::auth->assert('invoice_edit', 1) && !$::auth->assert('sales_invoice_view', 1))) {
     my $permission_where_str = @permission_where ? "OR (" . join(" AND ", map { "($_)" } @permission_where) . ")" : "";
     $where .= qq|
       AND (   (a.globalproject_id IN (
@@ -571,11 +573,11 @@ sub ar_transactions {
     $where .= " AND c.business_id = ?";
     push(@values, $business_id);
   }
-  if ($form->{department_id}) {
-    $where .= " AND a.department_id = ?";
-    push(@values, $form->{department_id});
+  if ($form->{taxzone_id}) {
+    $where .= " AND a.taxzone_id = ?";
+    push(@values, $form->{taxzone_id});
   }
-  foreach my $column (qw(invnumber ordnumber cusordnumber notes transaction_description)) {
+  foreach my $column (qw(invnumber ordnumber cusordnumber notes transaction_description shipvia shippingpoint)) {
     if ($form->{$column}) {
       $where .= " AND a.$column ILIKE ?";
       push(@values, like($form->{$column}));
@@ -683,7 +685,7 @@ SQL
   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
   my $sortorder = join(', ', map { "$_ $sortdir" } @a);
 
-  if (grep({ $_ eq $form->{sort} } qw(id transdate duedate invnumber ordnumber cusordnumber donumber deliverydate name datepaid employee shippingpoint shipvia transaction_description department))) {
+  if (grep({ $_ eq $form->{sort} } qw(id transdate duedate invnumber ordnumber cusordnumber donumber deliverydate name datepaid employee shippingpoint shipvia transaction_description department taxzone))) {
     $sortorder = $form->{sort} . " $sortdir";
   }
 
diff --git a/SL/BackgroundJob/CreateOrUpdateFileFullTexts.pm b/SL/BackgroundJob/CreateOrUpdateFileFullTexts.pm
new file mode 100644 (file)
index 0000000..055accd
--- /dev/null
@@ -0,0 +1,144 @@
+package SL::BackgroundJob::CreateOrUpdateFileFullTexts;
+
+use strict;
+
+use parent qw(SL::BackgroundJob::Base);
+
+use Encode qw(decode);
+use English qw( -no_match_vars );
+use File::Slurp qw(read_file);
+use List::MoreUtils qw(uniq);
+use IPC::Run qw();
+use Unicode::Normalize qw();
+
+use SL::DB::File;
+use SL::DB::FileFullText;
+use SL::HTML::Util;
+
+my %extractor_by_mime_type = (
+  'application/pdf' => \&_pdf_to_strings,
+  'text/html'       => \&_html_to_strings,
+  'text/plain'      => \&_text_to_strings,
+);
+
+sub create_job {
+  $_[0]->create_standard_job('20 3 * * *'); # # every day at 3:20 am
+}
+
+#
+# If job does not throw an error,
+# success in background_job_histories is 'success'.
+# It is 'failure' otherwise.
+#
+# return value goes to result in background_job_histories
+#
+sub run {
+  my $self    = shift;
+  my $db_obj  = shift;
+
+  my $all_dbfiles = SL::DB::Manager::File->get_all;
+
+  foreach my $dbfile (@$all_dbfiles) {
+    next if $dbfile->full_text && (($dbfile->mtime || $dbfile->itime) <= ($dbfile->full_text->mtime || $dbfile->full_text->itime));
+    next if !defined $extractor_by_mime_type{$dbfile->mime_type};
+
+    my $file_name;
+    if (!eval { $file_name = SL::File->get(dbfile => $dbfile)->get_file(); 1; }) {
+      $::lxdebug->message(LXDebug::WARN(), "CreateOrUpdateFileFullTexts::run: get_file failed: " . $EVAL_ERROR);
+      next;
+    }
+
+    my $text = $extractor_by_mime_type{$dbfile->mime_type}->($file_name);
+
+    if ($dbfile->full_text) {
+      $dbfile->full_text->update_attributes(full_text => $text);
+    } else {
+      SL::DB::FileFullText->new(file => $dbfile, full_text => $text)->save;
+    }
+  }
+
+  return 'ok';
+}
+
+sub _pdf_to_strings {
+  my ($file_name) = @_;
+
+  my   @cmd = qw(pdftotext -enc UTF-8);
+  push @cmd,  $file_name;
+  push @cmd,  '-';
+
+  my ($txt, $err);
+
+  IPC::Run::run \@cmd, \undef, \$txt, \$err;
+
+  if ($CHILD_ERROR) {
+    $::lxdebug->message(LXDebug::WARN(), "CreateOrUpdateFileFullTexts::_pdf_to_text failed for '$file_name': " . ($CHILD_ERROR >> 8) . ": " . $err);
+    return '';
+  }
+
+  $txt = Encode::decode('utf-8-strict', $txt);
+  $txt =~ s{\r}{ }g;
+  $txt =~ s{\p{WSpace}+}{ }g;
+  $txt = Unicode::Normalize::normalize('C', $txt);
+  $txt = join ' ' , uniq(split(' ', $txt));
+
+  return $txt;
+}
+
+sub _html_to_strings {
+  my ($file_name) = @_;
+
+  my $txt = read_file($file_name);
+
+  $txt = Encode::decode('utf-8-strict', $txt);
+  $txt = SL::HTML::Util::strip($txt);
+  $txt =~ s{\r}{ }g;
+  $txt =~ s{\p{WSpace}+}{ }g;
+  $txt = Unicode::Normalize::normalize('C', $txt);
+  $txt = join ' ' , uniq(split(' ', $txt));
+
+  return $txt;
+}
+
+sub _text_to_strings {
+  my ($file_name) = @_;
+
+  my $txt = read_file($file_name);
+
+  $txt = Encode::decode('utf-8-strict', $txt);
+  $txt =~ s{\r}{ }g;
+  $txt =~ s{\p{WSpace}+}{ }g;
+  $txt = Unicode::Normalize::normalize('C', $txt);
+  $txt = join ' ' , uniq(split(' ', $txt));
+
+  return $txt;
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::BackgroundJob::CreateOrUpdateFileFullTexts - Extract text strings/words from
+files in the DMS for full text search.
+
+=head1 SYNOPSIS
+
+Search all documents in the files table and try to extract strings from them
+and store the strings in the database.
+
+Duplicate strings/words in one text are removed.
+
+Strings are updated if the change or creation time of the document is newer than
+the old entry.
+
+=head1 AUTHOR
+
+Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
+
+=cut
index 6151ec1..4e32063 100644 (file)
@@ -143,8 +143,10 @@ sub _replace_vars {
   my $sub_fmt  = lc($params{attribute_format} // 'text');
 
   my ($start_tag, $end_tag) = $sub_fmt eq 'html' ? ('&lt;%', '%&gt;') : ('<%', '%>');
+  my @invoice_keys          = $params{invoice} ? (map { $_->name } $params{invoice}->meta->columns) : ();
+  my $key_name_re           = join '|', map { quotemeta } (@invoice_keys, keys %{ $params{vars} });
 
-  $str =~ s{ ${start_tag} ([a-z0-9_]+) ( \s+ format \s*=\s* (.*?) \s* )? ${end_tag} }{
+  $str =~ s{ ${start_tag} ($key_name_re) ( \s+ format \s*=\s* (.*?) \s* )? ${end_tag} }{
     my ($key, $format) = ($1, $3);
     $key               = $::locale->unquote_special_chars('html', $key) if $sub_fmt eq 'html';
     my $new_value;
@@ -449,6 +451,7 @@ sub _email_invoice {
       longdescription => 'html',
       partnotes       => 'html',
       notes           => 'html',
+      $::form->get_variable_content_types_for_cvars,
     },
   );
 
@@ -470,7 +473,7 @@ sub _email_invoice {
         invoice          => $data->{invoice},
         vars             => $data->{time_period_vars},
         attribute        => $_,
-        attribute_format => 'text'
+        attribute_format => ($_ eq 'email_body' ? 'html' : 'text')
       );
     }
 
@@ -486,6 +489,8 @@ sub _email_invoice {
       $mail->{bcc}         = $global_bcc;
       $mail->{subject}     = $data->{config}->email_subject;
       $mail->{message}     = $data->{config}->email_body;
+      $mail->{message}    .= SL::DB::Default->get->signature;
+      $mail->{content_type} = 'text/html';
       $mail->{attachments} = [{
         path     => $pdf_file_name,
         name     => sprintf('%s %s.pdf', $label, $data->{invoice}->invnumber),
index 0ab03bd..4cc2519 100644 (file)
@@ -11,6 +11,7 @@ use SL::DB::Invoice;
 use SL::DB::Printer;
 use SL::SessionFile;
 use SL::Template;
+use SL::ARAP;
 use SL::Locale::String qw(t8);
 use SL::Helper::MassPrintCreatePDF qw(:all);
 use SL::Helper::CreatePDF qw(:all);
@@ -41,6 +42,7 @@ sub create_invoices {
 
   my $job_obj = $self->{job_obj};
   my $db      = $job_obj->db;
+  my $dbh     = $db->dbh;
 
   $job_obj->set_data(status => CONVERTING_DELIVERY_ORDERS())->save;
 
@@ -56,6 +58,25 @@ sub create_invoices {
 
       die $db->error if !$invoice;
 
+      ARAP->close_orders_if_billed('dbh'     => $dbh,
+                                   'arap_id' => $invoice->id,
+                                   'table'   => 'ar',);
+
+      # update shop status
+      my @linked_shop_orders = $invoice->linked_records(
+        from      => 'ShopOrder',
+        via       => [ 'DeliveryOrder', 'Order' ],
+      );
+      #if (scalar @linked_shop_orders[0][0] >= 1){
+        #do update
+      my $shop_order = $linked_shop_orders[0][0];
+      if ($shop_order){
+      require SL::Shop;
+        my $shop_config = SL::DB::Manager::Shop->get_first( query => [ id => $shop_order->shop_id ] );
+        my $shop = SL::Shop->new( config => $shop_config );
+        $shop->connector->set_orderstatus($shop_order->shop_trans_id, "completed");
+      }
+
       $data->{num_created}++;
       push @{ $data->{invoice_ids} }, $invoice->id;
       push @{ $self->{invoices}    }, $invoice;
index 9eda722..ab145ce 100644 (file)
@@ -472,6 +472,7 @@ sub check_ar_acc_trans_amount {
           from acc_trans ac left join ar on (ac.trans_id = ar.id)
           WHERE ac.chart_link like 'AR_amount%'
           AND ac.transdate >= ? AND ac.transdate <= ?
+          AND ar.type       = 'invoice'
           group by invnumber,netamount having sum(ac.amount) <> ar.netamount|;
 
   my $ar_amount_not_ac_amount = selectall_hashref_query($::form, $self->dbh, $query, $self->fromdate, $self->todate);
index 031ef11..b52c879 100644 (file)
--- a/SL/CT.pm
+++ b/SL/CT.pm
@@ -42,6 +42,7 @@ use SL::Common;
 use SL::CVar;
 use SL::DBUtils;
 use SL::DB;
+use SL::Util qw(trim);
 use Text::ParseWords;
 
 use strict;
@@ -244,6 +245,28 @@ sub search {
     push @values, $form->{create_zugferd_invoices};
   }
 
+  if ($form->{all_phonenumbers}) {
+    my $search_term = trim($form->{all_phonenumbers});
+    $search_term    =~ s{\p{WSpace}+}{}g;
+    $search_term    = join ' *', split(//, $search_term);
+
+    $where .= qq| AND (ct.phone ~* ? OR
+                       ct.fax   ~* ? OR
+                       ct.id    IN
+                         (SELECT cp_cv_id FROM contacts
+                          WHERE cp_phone1      ~* ? OR
+                                cp_phone2      ~* ? OR
+                                cp_fax         ~* ? OR
+                                cp_mobile1     ~* ? OR
+                                cp_mobile2     ~* ? OR
+                                cp_satphone    ~* ? OR
+                                cp_satfax      ~* ? OR
+                                cp_privatphone ~* ?
+                         )
+    )|;
+    push @values, ($search_term)x10;
+  }
+
   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'CT',
                                                             'trans_id_field' => 'ct.id',
                                                             'filter'         => $form);
@@ -289,6 +312,7 @@ sub search {
         qq|SELECT ct.*, ct.itime::DATE AS insertdate, b.description AS business, e.name as salesman, | .
         qq|  pt.description as payment | .
         $pg_select .
+        $main_cp_select .
         qq|, a.invnumber, a.ordnumber, a.quonumber, a.id AS invid, | .
         qq|  '$module' AS module, 'invoice' AS formtype, | .
         qq|  (a.amount = a.paid) AS closed | .
@@ -308,6 +332,7 @@ sub search {
         qq|SELECT ct.*, ct.itime::DATE AS insertdate, b.description AS business, e.name as salesman, | .
         qq|  pt.description as payment | .
         $pg_select .
+        $main_cp_select .
         qq|, ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
         qq|  'oe' AS module, 'order' AS formtype, o.closed | .
         qq|FROM $cv ct | .
@@ -326,6 +351,7 @@ sub search {
         qq|SELECT ct.*, ct.itime::DATE AS insertdate, b.description AS business, e.name as salesman, | .
         qq|  pt.description as payment | .
         $pg_select .
+        $main_cp_select .
         qq|, ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
         qq|  'oe' AS module, 'quotation' AS formtype, o.closed | .
         qq|FROM $cv ct | .
index a905ede..637f129 100644 (file)
@@ -10,6 +10,7 @@ use Data::Dumper;
 
 use SL::DBUtils;
 use SL::MoreCommon qw(listify);
+use SL::Presenter::Text;
 use SL::Util qw(trim);
 use SL::DB;
 
@@ -46,7 +47,7 @@ SQL
       } elsif ($config->{type} eq 'number') {
         $config->{precision} = $1 if ($config->{options} =~ m/precision=(\d+)/i);
 
-      } elsif ($config->{type} eq 'textfield') {
+      } elsif ($config->{type} =~ m{^(?:html|text)field$}) {
         $config->{width}  = 30;
         $config->{height} =  5;
         $config->{width}  = $1 if ($config->{options} =~ m/width=(\d+)/i);
@@ -112,7 +113,7 @@ sub get_custom_variables {
   my $custom_variables = $self->get_configs(module => $params{module});
 
   foreach my $cvar (@{ $custom_variables }) {
-    if ($cvar->{type} eq 'textfield') {
+    if ($cvar->{type} =~ m{^(?:html|text)field}) {
       $cvar->{width}  = 30;
       $cvar->{height} =  5;
 
@@ -271,7 +272,7 @@ sub _save_custom_variables {
 
     my $value  = $params{variables}->{"$params{name_prefix}cvar_$config->{name}$params{name_postfix}"};
 
-    if (($config->{type} eq 'text') || ($config->{type} eq 'textfield') || ($config->{type} eq 'select')) {
+    if (any { $config->{type} eq $_ } qw(text textfield htmlfield select)) {
       push @values, undef, undef, $value, undef;
 
     } elsif (($config->{type} eq 'date') || ($config->{type} eq 'timestamp')) {
@@ -375,7 +376,7 @@ sub build_filter_query {
 
     my (@sub_values, @sub_where, $not);
 
-    if (($config->{type} eq 'text') || ($config->{type} eq 'textfield')) {
+    if (any { $config->{type} eq $_ } qw(text textfield htmlfield)) {
       next unless ($params{filter}->{$name});
 
       push @sub_where,  qq|cvar.text_value ILIKE ?|;
@@ -525,6 +526,7 @@ sub add_custom_variables_to_report {
         : $cfg->{type} eq 'vendor'    ? (SL::DB::Manager::Vendor->find_by(id => 1*$ref->{number_value})   || SL::DB::Vendor->new)->name
         : $cfg->{type} eq 'part'      ? (SL::DB::Manager::Part->find_by(id => 1*$ref->{number_value})     || SL::DB::Part->new)->partnumber
         : $cfg->{type} eq 'bool'      ? ($ref->{bool_value} ? $locale->text('Yes') : $locale->text('No'))
+        : $cfg->{type} eq 'htmlfield' ? SL::Presenter::Text::stripped_html($ref->{text_value})
         :                               $ref->{text_value};
     }
   }
diff --git a/SL/Clipboard/Base.pm b/SL/Clipboard/Base.pm
deleted file mode 100644 (file)
index fc0a16a..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-package SL::Clipboard::Base;
-
-use strict;
-
-use parent qw(Rose::Object);
-
-use Rose::Object::MakeMethods::Generic (
-  'scalar --get_set_init' => [ qw(content timestamp) ],
-);
-
-use Rose::DB::Object::Helpers ();
-
-sub init_timestamp { die "'timestamp' property not set"; }
-sub init_content   { die "'content' property not set";   }
-
-sub type {
-  my ($self_or_class) = @_;
-  return (split m/::/, ref($self_or_class) ? ref($self_or_class) : $self_or_class)[-1];
-}
-
-sub reload_object {
-  my ($self, $object) = @_;
-
-  return ref($object)->new(map { $_ => $object->$_ } $object->meta->primary_key)->load;
-}
-
-sub as_tree {
-  my ($self, $object, %params) = @_;
-
-  my $tree = Rose::DB::Object::Helpers::as_tree($object, %params);
-  $self->_fix_tree($tree, $object);
-  return $tree;
-}
-
-sub to_object {
-  my ($self) = @_;
-  my $object = Rose::DB::Object::Helpers::new_from_tree("SL::DB::" . $self->type, $self->content);
-
-  # Reset primary key columns and itime/mtime if the class supports it.
-  foreach ($object->meta->primary_key, 'itime', 'mtime') {
-    $object->$_(undef) if $object->can($_);
-  }
-
-  # Let sub classes fix the objects further.
-  $self->_fix_object($object);
-  return $object;
-}
-
-sub dump {
-  my ($self, $object) = @_;
-  return $self->as_tree($self->reload_object($object), max_depth => 1);
-}
-
-sub describe {
-  die "'describe' method not overwritten by derived class";
-}
-
-sub _fix_object {
-  my ($self, $object) = @_;
-  # To be overwritten by child classes.
-}
-
-sub _fix_tree {
-  my ($self, $tree, $object) = @_;
-
-  # Delete primary key columns and itime/mtime if the class supports it.
-  foreach ($object->meta->primary_key, 'itime', 'mtime') {
-    delete $tree->{$_} if $object->can($_);
-  }
-}
-
-sub _binary_column_names {
-  my ($self, $class) = @_;
-  return map  { $_->name }
-         grep { ref($_) =~ m/Pg::Bytea$/i }
-         @{ $class->meta->columns };
-}
-
-1;
-__END__
-
-=pod
-
-=encoding utf8
-
-=head1 NAME
-
-SL::Clipboard::Base - Base class for clipboard specialization classes
-
-=head1 SYNOPSIS
-
-See the synopsis of L<SL::Clipboard>.
-
-=head1 OVERVIEW
-
-This is a base class providing a lot of utility and
-defaults. Sub-classes must overwrite at least the function
-L</describe> but can overwrite others as well.
-
-Writing a specialized sub-class for a database type involves
-overwriting one or more functions. These are:
-
-=over 4
-
-=item * C<describe>
-
-Must be overwritten. Returns a human-readable description of the
-content. Should only be one line.
-
-=item * C<dump>
-
-Optional. Overwrite if sub-class needs to dump more/less than the
-implementation in this class dumps.
-
-=item * C<_fix_object>
-
-Optional. Overwrite if re-created Rose::DB::Object instances must be
-cleaned further before they're returned to the caller.
-
-=item * C<_fix_tree>
-
-Optional. Overwrite if the tree created during a copy operation of a
-Rose::DB::Object instance must be cleaned further before it's stored.
-
-=back
-
-You don't have to or should not overwrite the other functions:
-
-=over 4
-
-=item * C<as_tree>
-
-=item * C<reload_object>
-
-=item * C<to_object>
-
-=item * C<type>
-
-=back
-
-Don't forget to C<use> the specialized module here in Base!
-
-=head1 FUNCTIONS
-
-=over 4
-
-=item C<as_tree $object, %params>
-
-A convenience function calling L<Rose::DB::Object::Helpers/as_tree>
-with C<$object> and C<%params> as parameters. Returns a hash/array
-reference tree of the function.
-
-Don't overwrite this function in sub-classes. Overwrite L</dump>
-instead.
-
-=item C<describe>
-
-Returns a human-readable description of the content. This should only
-be a single line without any markup.
-
-Sub-classes must overwrite this function.
-
-=item C<dump $object>
-
-Dumps the object as a hash/array tree and returns it by calling
-L<Rose::DB::Object::Helpers/as_tree>. The default implementation
-reloads the object first by calling L</reload_object>. It also only
-dumps the object itself, not any of the relationships, by calling
-C<as_tree> with the parameter C<max_depth =E<gt> 1>.
-
-Overwrite this in a sub-class if you need to dump more or differently
-(see L<SL::Clipboard::RequirementSpecItem> for an example).
-
-=item C<reload_object $object>
-
-Reloads C<$object> from the database and returns a new instance. Can
-be useful for sanitizing the object given to L</dump> before
-converting into a tree. It is used by the default implementation of
-L</dump>.
-
-=item C<to_object>
-
-Converts the dumped representation back to a Rose::DB::Object
-instance. Several columns of the newly created object are cleared by
-C<to_object> itself: the primary key columns (if any) and the columns
-C<itime> and C<mtime> (if the object has such columns).
-
-This function should not be overwritten by sub-classes. Instead,
-functions can overwrite C<_fix_object> which can be used for sanitizing
-the newly created object before handing it back to the caller.
-
-=item C<type>
-
-Returns the actual clipped type (e.g. C<RequirementSpecItem>). This is
-derived from the actual class name of C<$self>.
-
-=item C<_binary_column_names $class>
-
-Returns an array of column names that have a binary type. Useful for
-sub-classes which need to encode binary content in Base64 during
-C<dump>.
-
-=item C<_fix_object $object>
-
-This function is called by L</to_object> before the object is passed
-back to the caller. It does not do anything in the default
-implementation, but sub-classes are free to overwrite it if they need
-to sanitize the object. See L<SL::Clipboard::RequirementSpecItem> for
-an example.
-
-Its return value is ignored.
-
-=item C<_fix_tree $tree, $object>
-
-This function is called by L</as_tree> after dumping and before the
-object is stored during a copy operation. In the default
-implementation all primary key columns and the columns C<itime> and
-C<mtime> (if the object has such columns) are removed from the tree.
-Sub-classes are free to overwrite it if they need to sanitize the
-tree. See L<SL::Clipboard::RequirementSpecItem> for an example.
-
-C<$object> is just passed in for reference and should not be modified.
-
-Its return value is ignored.
-
-=back
-
-=head1 BUGS
-
-Nothing here yet.
-
-=head1 AUTHOR
-
-Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
-
-=cut
diff --git a/SL/Clipboard/RequirementSpecItem.pm b/SL/Clipboard/RequirementSpecItem.pm
deleted file mode 100644 (file)
index 85bd5d9..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-package SL::Clipboard::RequirementSpecItem;
-
-use strict;
-
-use parent qw(SL::Clipboard::Base);
-
-use List::Util qw(sum);
-
-use SL::Common;
-use SL::Locale::String;
-
-sub dump {
-  my ($self, $object) = @_;
-
-  return $self->as_tree(_load_children($self->reload_object($object)), exclude => sub { ref($_[0]) !~ m/::RequirementSpecItem$/ });
-}
-
-sub describe {
-  my ($self) = @_;
-
-  my $item              = $self->content;
-  my $num_children      = @{ $item->{children} || [] };
-  my $num_grandchildren = sum map { scalar(@{ $_->{children} || [] }) } @{ $item->{children} || [] };
-
-  if ($item->{item_type} eq 'section') {
-    return t8('Requirement spec section #1 "#2" with #3 function blocks and a total of #4 sub function blocks; preamble: "#5"',
-              $item->{fb_number}, $item->{title}, $num_children, $num_grandchildren, Common::truncate($item->{description}, strip => 'full'));
-  } elsif ($item->{item_type} eq 'function-block') {
-    return t8('Requirement spec function block #1 with #2 sub function blocks; description: "#3"',
-              $item->{fb_number}, $num_children, Common::truncate($item->{description}, strip => 'full'));
-  } else {
-    return t8('Requirement spec sub function block #1; description: "#2"',
-              $item->{fb_number}, Common::truncate($item->{description}, strip => 'full'));
-  }
-}
-
-sub _load_children {
-  my ($object) = @_;
-
-  _load_children($_) for @{ $object->children };
-
-  return $object;
-}
-
-sub _fix_object {
-  my ($self, $object) = @_;
-
-  $object->$_(undef)     for qw(fb_number);
-  $self->_fix_object($_) for @{ $object->children || [] };
-}
-
-sub _fix_tree {
-  my ($self, $tree, $object) = @_;
-
-  delete @{ $tree }{ qw(id itime mtime parent_id position requirement_spec_id) };
-  $self->_fix_tree($_) for @{ $tree->{children} || [] };
-}
-
-1;
-__END__
-
-=pod
-
-=encoding utf8
-
-=head1 NAME
-
-SL::Clipboard::RequirementSpecItem - Clipboard specialization for
-SL::DB::RequirementSpecItem
-
-=head1 FUNCTIONS
-
-=over 4
-
-=item C<describe>
-
-Returns a human-readable description depending on the copied type
-(section, function block or sub function block).
-
-=item C<dump $object>
-
-This specialization reloads C<$object> from the database, loads all of
-its children (but only the other requirement spec items, no other
-relationships) and dumps it.
-
-=item C<_fix_object $object>
-
-Fixes C<$object> and all of its children by clearing certain columns
-like the position or function block numbers.
-
-=back
-
-=head1 BUGS
-
-Nothing here yet.
-
-=head1 AUTHOR
-
-Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
-
-=cut
diff --git a/SL/Clipboard/RequirementSpecPicture.pm b/SL/Clipboard/RequirementSpecPicture.pm
deleted file mode 100644 (file)
index 7a3757f..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-package SL::Clipboard::RequirementSpecPicture;
-
-use strict;
-
-use parent qw(SL::Clipboard::Base);
-
-use SL::Common;
-use SL::Locale::String;
-use MIME::Base64;
-
-sub dump {
-  my ($self, $object) = @_;
-
-  $self->reload_object($object);
-
-  my $tree    = $self->as_tree($object, exclude => sub { ref($_[0]) !~ m/::RequirementSpecPicture$/ });
-  $tree->{$_} = encode_base64($tree->{$_}, '') for $self->_binary_column_names('SL::DB::RequirementSpecPicture');
-
-  return $tree;
-}
-
-sub describe {
-  my ($self) = @_;
-
-  return t8('Requirement spec picture "#1"', $self->content->{description} ? $self->content->{description} . ' (' . $self->content->{picture_file_name} . ')' : $self->content->{picture_file_name});
-}
-
-sub _fix_object {
-  my ($self, $object) = @_;
-
-  $object->$_(undef) for qw(number);
-  $object->$_(decode_base64($object->$_)) for $self->_binary_column_names('SL::DB::RequirementSpecPicture');
-
-  return $object;
-}
-
-1;
-__END__
-
-=pod
-
-=encoding utf8
-
-=head1 NAME
-
-SL::Clipboard::RequirementSpecPicture - Clipboard specialization for
-SL::DB::RequirementSpecPicture
-
-=head1 NOTES
-
-The underlying RDBO model contains binary columns, but binary data
-cannot be dumped as YAML. Therefore the binary content is encoded in
-Base64 in L</dump> and decoded back to binary form in L</_fix_object>.
-
-=head1 FUNCTIONS
-
-=over 4
-
-=item C<describe>
-
-Returns a human-readable description including the title and an
-excerpt of its content.
-
-=item C<dump $object>
-
-This specialization reloads C<$object> from the database, and dumps
-it. Binary columns are dumped encoded in Base64.
-
-=item C<_fix_object $object>
-
-Fixes C<$object> by clearing certain columns like the number. Also
-decodes binary columns from Base64 back to binary.
-
-=back
-
-=head1 BUGS
-
-Nothing here yet.
-
-=head1 AUTHOR
-
-Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
-
-=cut
diff --git a/SL/Clipboard/RequirementSpecTextBlock.pm b/SL/Clipboard/RequirementSpecTextBlock.pm
deleted file mode 100644 (file)
index 4b40a8e..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-package SL::Clipboard::RequirementSpecTextBlock;
-
-use strict;
-
-use parent qw(SL::Clipboard::Base);
-
-use SL::Clipboard::RequirementSpecPicture;
-use SL::Common;
-use SL::Locale::String;
-
-sub dump {
-  my ($self, $object) = @_;
-
-  $self->reload_object($object);
-
-  my $tree          = $self->as_tree($object, exclude => sub { ref($_[0]) !~ m/::RequirementSpecTextBlock$/ });
-  $tree->{pictures} = [ map { SL::Clipboard::RequirementSpecPicture->new->dump($_) } @{ $object->pictures } ];
-
-  return $tree;
-}
-
-sub describe {
-  my ($self) = @_;
-
-  return t8('Requirement spec text block "#1"; content: "#2"', $self->content->{title}, Common::truncate($self->content->{text}, strip => 'full'));
-}
-
-sub _fix_object {
-  my ($self, $object) = @_;
-
-  $object->$_(undef) for qw(output_position position requirement_spec_id);
-
-  SL::Clipboard::RequirementSpecPicture->new->_fix_object($_) for @{ $object->pictures || [] };
-
-  return $object;
-}
-
-1;
-__END__
-
-=pod
-
-=encoding utf8
-
-=head1 NAME
-
-SL::Clipboard::RequirementSpecTextBlock - Clipboard specialization for
-SL::DB::RequirementSpecTextBlock
-
-=head1 FUNCTIONS
-
-=over 4
-
-=item C<describe>
-
-Returns a human-readable description including the title and an
-excerpt of its content.
-
-=item C<dump $object>
-
-This specialization reloads C<$object> from the database, loads all of
-its pictures and dumps it. The pictures are dumped using the clipboard
-specialization for it, L<SL::Clipboard::RequirementSpecPicture/dump>.
-
-=item C<_fix_object $object>
-
-Fixes C<$object> by clearing certain columns like the position. Lets
-pictures be fixed by the clipboard specialization for it,
-L<SL::Clipboard::RequirementSpecPicture/_fix_object>.
-
-=back
-
-=head1 BUGS
-
-Nothing here yet.
-
-=head1 AUTHOR
-
-Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
-
-=cut
index fb1b4b8..126a30e 100644 (file)
@@ -25,6 +25,7 @@ use Encode qw(decode);
 
 use SL::DBUtils;
 use SL::DB;
+use SL::HTML::Util;
 
 sub unique_id {
   my ($a, $b) = gettimeofday();
@@ -342,6 +343,11 @@ sub get_vc_details {
   $query = qq|SELECT * FROM shipto WHERE (trans_id = ?)|;
   $form->{SHIPTO} = selectall_hashref_query($form, $dbh, $query, $vc_id);
 
+  if ($vc eq 'customer') {
+    $query = qq|SELECT * FROM additional_billing_addresses WHERE (customer_id = ?)|;
+    $form->{ADDITIONAL_BILLING_ADDRESSES} = selectall_hashref_query($form, $dbh, $query, $vc_id);
+  }
+
   $query = qq|SELECT * FROM contacts WHERE (cp_cv_id = ?)|;
   $form->{CONTACTS} = selectall_hashref_query($form, $dbh, $query, $vc_id);
 
@@ -382,6 +388,8 @@ sub save_email_status {
 
   my ($self, $myconfig, $form) = @_;
 
+  return unless ($::instance_conf->get_email_journal);
+
   my ($table, $query, $dbh);
 
   if ($form->{script} eq 'oe.pl') {
@@ -418,7 +426,7 @@ sub save_email_status {
       . $main::locale->text('To (email)') . ": $form->{email}\n"
       . "${cc}${bcc}"
       . $main::locale->text('Subject') . ": $form->{subject}\n\n"
-      . $main::locale->text('Message') . ": $form->{message}";
+      . $main::locale->text('Message') . ": " . SL::HTML::Util->strip($form->{message});
 
     $intnotes =~ s|\r||g;
 
@@ -588,8 +596,10 @@ sub copy_file_to_webdav_folder {
     return;
   }
 
+  $form->{attachment_filename} ||= $form->generate_attachment_filename;
+
   my $timestamp =  get_current_formatted_time();
-  my $new_file  =  File::Spec->catfile($form->{cwd}, $webdav_folder, $form->generate_attachment_filename());
+  my $new_file  =  File::Spec->catfile($form->{cwd}, $webdav_folder, $form->{attachment_filename});
   $new_file =~ s{(.*)\.}{$1$timestamp\.};
 
   if (!File::Copy::copy($current_file, $new_file)) {
@@ -638,6 +648,11 @@ C<full> (replace consecutive line feed/carriage return characters in
 the middle by a single space and remove tailing line feed/carriage
 return characters).
 
+=item C<save_email_status>
+
+Adds sending information to internal notes.
+Does nothing if the client config email_journal is enabled.
+
 =back
 
 =head1 BUGS
index e620089..c22fdca 100644 (file)
@@ -592,6 +592,13 @@ sub use_multiselect_js {
   return $self;
 }
 
+sub use_ckeditor_js {
+  my ($self) = @_;
+
+  $::request->{layout}->use_javascript("${_}.js") for qw(ckeditor/ckeditor ckeditor/adapters/jquery);
+  return $self;
+}
+
 sub login_form {
   my ($self, %params) = @_;
   $::request->layout(SL::Layout::AdminLogin->new);
@@ -601,7 +608,7 @@ sub login_form {
 
 sub edit_user_form {
   my ($self, %params) = @_;
-  $self->use_multiselect_js->render('admin/edit_user', %params);
+  $self->use_multiselect_js->use_ckeditor_js->render('admin/edit_user', %params);
 }
 
 sub edit_client_form {
index d340216..9d432d5 100644 (file)
@@ -90,24 +90,28 @@ sub gather_bank_transactions_and_proposals {
     sort_by      => $sort_by,
     limit        => 10000,
     where        => [
-      amount                => {ne => \'invoice_amount'},
+      amount                => {ne => \'invoice_amount'},      # '} make emacs happy
       local_bank_account_id => $params{bank_account}->id,
       cleared               => 0,
       @where
     ],
   );
   # credit notes have a negative amount, treat differently
-  my $all_open_ar_invoices = SL::DB::Manager::Invoice        ->get_all(where => [ or => [ amount => { gt => \'paid' },
-                                                                                          and => [ type    => 'credit_note',
-                                                                                                   amount  => { lt => \'paid' }
-                                                                                                 ],
-                                                                                        ],
-                                                                                ],
-                                                                       with_objects => ['customer','payment_terms']);
-
-  my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where => [amount => { ne => \'paid' }], with_objects => ['vendor'  ,'payment_terms']);
-  my $all_open_sepa_export_items = SL::DB::Manager::SepaExportItem->get_all(where => [chart_id => $params{bank_account}->chart_id ,
-                                                                             'sepa_export.executed' => 0, 'sepa_export.closed' => 0 ], with_objects => ['sepa_export']);
+  my $all_open_ar_invoices = SL::DB::Manager::Invoice->get_all(where        => [ or => [ amount => { gt => \'paid' },                 # '} make emacs happy
+                                                                                         and    => [ type    => 'credit_note',
+                                                                                                     amount  => { lt => \'paid' }     # '} make emacs happy
+                                                                                         ],
+                                                                                 ],
+                                                               ],
+                                                               with_objects => ['customer','payment_terms']);
+
+  my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where        => [amount => { ne => \'paid' }],                 #  '}] make emacs happy
+                                                                       with_objects => ['vendor'  ,'payment_terms']);
+  my $all_open_sepa_export_items = SL::DB::Manager::SepaExportItem->get_all(where        => [chart_id               => $params{bank_account}->chart_id ,
+                                                                                             'sepa_export.executed' => 0,
+                                                                                             'sepa_export.closed'   => 0
+                                                                            ],
+                                                                            with_objects => ['sepa_export']);
 
   my @all_open_invoices;
   # filter out invoices with less than 1 cent outstanding
@@ -274,12 +278,14 @@ sub action_create_invoice {
 
   my $templates_ap = SL::DB::Manager::RecordTemplate->get_all(
     where        => [ template_type => 'ap_transaction' ],
+    sort_by      => [ qw(template_name) ],
     with_objects => [ qw(employee vendor) ],
   );
   my $templates_gl = SL::DB::Manager::RecordTemplate->get_all(
     query        => [ template_type => 'gl_transaction',
                       chart_id      => SL::DB::Manager::BankAccount->find_by(id => $self->transaction->local_bank_account_id)->chart_id,
                     ],
+    sort_by      => [ qw(template_name) ],
     with_objects => [ qw(employee record_template_items) ],
   );
 
@@ -293,14 +299,21 @@ sub action_create_invoice {
     'filter.fromdate'     => $::form->{filter}->{fromdate},
   ));
 
-  $self->render(
-    'bank_transactions/create_invoice',
-    { layout => 0 },
-    title        => t8('Create invoice'),
-    TEMPLATES_GL => $use_vendor_filter && @{ $templates_ap } ? undef : $templates_gl,
-    TEMPLATES_AP => $templates_ap,
-    vendor_name  => $use_vendor_filter && @{ $templates_ap } ? $vendor_of_transaction->name : undef,
-  );
+  # if we have exactly one ap match, use this directly
+  if (1 == scalar @{ $templates_ap }) {
+    $self->redirect_to($self->load_ap_record_template_url($templates_ap->[0]));
+
+  } else {
+    my $dialog_html = $self->render(
+      'bank_transactions/create_invoice',
+      { layout => 0, output => 0 },
+      title        => t8('Create invoice'),
+      TEMPLATES_GL => $use_vendor_filter && @{ $templates_ap } ? undef : $templates_gl,
+      TEMPLATES_AP => $templates_ap,
+      vendor_name  => $use_vendor_filter && @{ $templates_ap } ? $vendor_of_transaction->name : undef,
+    );
+    $self->js->run('kivi.BankTransaction.show_create_invoice_dialog', $dialog_html)->render;
+  }
 }
 
 sub action_ajax_payment_suggestion {
@@ -678,6 +691,7 @@ sub save_single_bank_transaction {
                           source        => $source,
                           memo          => $memo,
                           skonto_amount => $free_skonto_amount,
+                          bt_id         => $bt_id,
                           transdate     => $bank_transaction->valutadate->to_kivitendo);
     # ... and record the origin via BankTransactionAccTrans
     if (scalar(@acc_ids) < 2) {
@@ -969,6 +983,7 @@ sub load_ap_record_template_url {
     'form_defaults.paid_1_suggestion'    => $::form->format_amount(\%::myconfig, -1 * $self->transaction->amount, 2),
     'form_defaults.AP_paid_1_suggestion' => $self->transaction->local_bank_account->chart->accno,
     'form_defaults.callback'             => $self->callback,
+    'form_defaults.notes'                => $self->convert_purpose_for_template($template, $self->transaction->purpose),
   );
 }
 
@@ -984,10 +999,18 @@ sub load_gl_record_template_url {
     'form_defaults.callback'             => $self->callback,
     'form_defaults.bt_id'                => $self->transaction->id,
     'form_defaults.bt_chart_id'          => $self->transaction->local_bank_account->chart->id,
-    'form_defaults.description'          => $self->transaction->purpose,
+    'form_defaults.description'          => $self->convert_purpose_for_template($template, $self->transaction->purpose),
   );
 }
 
+sub convert_purpose_for_template {
+  my ($self, $template, $purpose) = @_;
+
+  # enter custom code here
+
+  return $purpose;
+}
+
 sub setup_search_action_bar {
   my ($self, %params) = @_;
 
@@ -1105,6 +1128,13 @@ GL-records will be deleted completely if a bank transaction was the source.
 
 TODO: we still rely on linked_records for the check boxes
 
+=item C<convert_purpose_for_template>
+
+This method can be used to parse, filter and convert the bank transaction's
+purpose string before it will be assigned to the description field of a
+gl transaction or to the notes field of an ap transaction.
+You have to write your own custom code.
+
 =back
 
 =head1 AUTHOR
index 5e0fd26..63f153f 100644 (file)
@@ -15,7 +15,7 @@ use SL::Presenter;
 use Rose::Object::MakeMethods::Generic
 (
   scalar                  => [ qw(action_name) ],
-  'scalar --get_set_init' => [ qw(js) ],
+  'scalar --get_set_init' => [ qw(js p) ],
 );
 
 #
@@ -184,6 +184,10 @@ sub presenter {
   return SL::Presenter->get;
 }
 
+sub init_p {
+  return SL::Presenter->get;
+}
+
 sub controller_name {
   my $class = ref($_[0]) || $_[0];
   $class    =~ s/^SL::Controller:://;
index 1212512..bc0f287 100644 (file)
@@ -246,7 +246,7 @@ sub check_auth {
 sub edit_form {
   my ($self) = @_;
 
-  $::request->layout->use_javascript("${_}.js") for qw(jquery.selectboxes jquery.multiselect2side kivi.File);
+  $::request->layout->use_javascript("${_}.js") for qw(jquery.selectboxes jquery.multiselect2side kivi.File ckeditor/ckeditor ckeditor/adapters/jquery);
 
   $self->setup_edit_form_action_bar;
   $self->render('client_config/form', title => t8('Client Configuration'),
index 06f4bc2..d1ff719 100644 (file)
@@ -13,6 +13,7 @@ use SL::Helper::Flash;
 use SL::Locale::String;
 use SL::SessionFile;
 use SL::SessionFile::Random;
+use SL::Controller::CsvImport::AdditionalBillingAddress;
 use SL::Controller::CsvImport::Contact;
 use SL::Controller::CsvImport::CustomerVendor;
 use SL::Controller::CsvImport::Part;
@@ -307,7 +308,7 @@ sub check_auth {
 sub check_type {
   my ($self) = @_;
 
-  die "Invalid CSV import type" if none { $_ eq $::form->{profile}->{type} } qw(parts inventories customers_vendors addresses contacts projects orders delivery_orders bank_transactions ar_transactions);
+  die "Invalid CSV import type" if none { $_ eq $::form->{profile}->{type} } qw(parts inventories customers_vendors billing_addresses addresses contacts projects orders delivery_orders bank_transactions ar_transactions);
   $self->type($::form->{profile}->{type});
 }
 
@@ -348,6 +349,7 @@ sub render_inputs {
   }
 
   my $title = $self->type eq 'customers_vendors' ? $::locale->text('CSV import: customers and vendors')
+            : $self->type eq 'billing_addresses' ? $::locale->text('CSV import: additional billing addresses')
             : $self->type eq 'addresses'         ? $::locale->text('CSV import: shipping addresses')
             : $self->type eq 'contacts'          ? $::locale->text('CSV import: contacts')
             : $self->type eq 'parts'             ? $::locale->text('CSV import: parts and services')
@@ -720,6 +722,7 @@ sub init_worker {
 
   return $self->{type} eq 'customers_vendors' ? SL::Controller::CsvImport::CustomerVendor->new(@args)
        : $self->{type} eq 'contacts'          ? SL::Controller::CsvImport::Contact->new(@args)
+       : $self->{type} eq 'billing_addresses' ? SL::Controller::CsvImport::AdditionalBillingAddress->new(@args)
        : $self->{type} eq 'addresses'         ? SL::Controller::CsvImport::Shipto->new(@args)
        : $self->{type} eq 'parts'             ? SL::Controller::CsvImport::Part->new(@args)
        : $self->{type} eq 'inventories'       ? SL::Controller::CsvImport::Inventory->new(@args)
diff --git a/SL/Controller/CsvImport/AdditionalBillingAddress.pm b/SL/Controller/CsvImport/AdditionalBillingAddress.pm
new file mode 100644 (file)
index 0000000..6d2d8ea
--- /dev/null
@@ -0,0 +1,90 @@
+package SL::Controller::CsvImport::AdditionalBillingAddress;
+
+use strict;
+
+use SL::Helper::Csv;
+
+use parent qw(SL::Controller::CsvImport::Base);
+
+use Rose::Object::MakeMethods::Generic
+(
+ scalar => [ qw(table) ],
+);
+
+sub set_profile_defaults {
+};
+
+sub init_class {
+  my ($self) = @_;
+  $self->class('SL::DB::AdditionalBillingAddress');
+}
+
+sub _hash_object {
+  my ($o) = @_;
+  return join('--', map({ s/[\s,\.\-]//g; $_ } ($o->name, $o->street)));
+}
+
+sub check_objects {
+  my ($self) = @_;
+
+  $self->controller->track_progress(phase => 'building data', progress => 0);
+
+  my %existing_by_id_name_street = map { (_hash_object($_) => $_) } @{ $self->existing_objects };
+  my $methods                    = $self->controller->headers->{methods};
+
+  my $i = 0;
+  my $num_data = scalar @{ $self->controller->data };
+  foreach my $entry (@{ $self->controller->data }) {
+    $self->controller->track_progress(progress => $i/$num_data * 100) if $i % 100 == 0;
+
+    $self->check_vc($entry, 'customer_id');
+
+    next if @{ $entry->{errors} };
+
+    my $object   = $entry->{object};
+    my $idx      = _hash_object($object);
+    my $existing = $existing_by_id_name_street{$idx};
+
+    if (!$existing) {
+      $existing_by_id_name_street{$idx} = $object;
+    } else {
+      $entry->{object_to_save} = $existing;
+
+      $existing->$_( $object->$_ ) for @{ $methods };
+
+      push @{ $entry->{information} }, $::locale->text('Updating existing entry in database');
+    }
+
+  } continue {
+    $i++;
+  }
+
+  $self->add_info_columns({ header => $::locale->text('Customer/Vendor'), method => 'vc_name' });
+}
+
+sub setup_displayable_columns {
+  my ($self) = @_;
+
+  $self->SUPER::setup_displayable_columns;
+
+  $self->add_displayable_columns(
+    { name => 'default_address', description => $::locale->text('Default address flag') },
+    { name => 'name',            description => $::locale->text('Name')                 },
+    { name => 'department_1',    description => $::locale->text('Department 1')         },
+    { name => 'department_2',    description => $::locale->text('Department 2')         },
+    { name => 'street',          description => $::locale->text('Street')               },
+    { name => 'zipcode',         description => $::locale->text('Zipcode')              },
+    { name => 'city',            description => $::locale->text('City')                 },
+    { name => 'country',         description => $::locale->text('Country')              },
+    { name => 'contact',         description => $::locale->text('Contact')              },
+    { name => 'email',           description => $::locale->text('E-mail')               },
+    { name => 'fax',             description => $::locale->text('Fax')                  },
+    { name => 'gln',             description => $::locale->text('GLN')                  },
+    { name => 'phone',           description => $::locale->text('Phone')                },
+    { name => 'customer_id',     description => $::locale->text('Customer')             },
+    { name => 'customer',        description => $::locale->text('Customer (name)')      },
+    { name => 'customernumber',  description => $::locale->text('Customer Number')      },
+  );
+}
+
+1;
index fe8af33..1aaec79 100644 (file)
@@ -293,6 +293,7 @@ sub handle_cvars {
 
   my %type_to_column = ( text      => 'text_value',
                          textfield => 'text_value',
+                         htmlfield => 'text_value',
                          select    => 'text_value',
                          date      => 'timestamp_value_as_date',
                          timestamp => 'timestamp_value_as_date',
@@ -539,9 +540,11 @@ sub save_objects {
     SL::DB->client->with_transaction(sub {
       foreach my $entry_index ($chunk_size * $chunk .. min( $last_index, $chunk_size * ($chunk + 1) - 1 )) {
         my $entry = $data->[$entry_index];
-        next if @{ $entry->{errors} };
 
         my $object = $entry->{object_to_save} || $entry->{object};
+        $self->save_additions_always($object);
+
+        next if @{ $entry->{errors} };
 
         my $ret;
         if (!eval { $ret = $object->save(cascade => !!$self->save_with_cascade()); 1 }) {
@@ -602,6 +605,18 @@ sub save_additions {
   return;
 }
 
+sub save_additions_always {
+  my ($self, $object) = @_;
+
+  # Can be overridden by derived specialized importer classes to save
+  # additional tables always.
+  # This sub is called before the object is saved. Therefore this
+  # hook will always be executed whether or not the import entry can be saved successfully.
+
+  return;
+}
+
+
 sub _save_history {
   my ($self, $object) = @_;
 
index 2632722..9ddb86b 100644 (file)
@@ -174,6 +174,7 @@ sub handle_cvars {
 
   my %type_to_column = ( text      => 'text_value',
                          textfield => 'text_value',
+                         htmlfield => 'text_value',
                          select    => 'text_value',
                          date      => 'timestamp_value_as_date',
                          timestamp => 'timestamp_value_as_date',
diff --git a/SL/Controller/CsvImport/Clipboard/Base.pm b/SL/Controller/CsvImport/Clipboard/Base.pm
new file mode 100644 (file)
index 0000000..fc0a16a
--- /dev/null
@@ -0,0 +1,236 @@
+package SL::Clipboard::Base;
+
+use strict;
+
+use parent qw(Rose::Object);
+
+use Rose::Object::MakeMethods::Generic (
+  'scalar --get_set_init' => [ qw(content timestamp) ],
+);
+
+use Rose::DB::Object::Helpers ();
+
+sub init_timestamp { die "'timestamp' property not set"; }
+sub init_content   { die "'content' property not set";   }
+
+sub type {
+  my ($self_or_class) = @_;
+  return (split m/::/, ref($self_or_class) ? ref($self_or_class) : $self_or_class)[-1];
+}
+
+sub reload_object {
+  my ($self, $object) = @_;
+
+  return ref($object)->new(map { $_ => $object->$_ } $object->meta->primary_key)->load;
+}
+
+sub as_tree {
+  my ($self, $object, %params) = @_;
+
+  my $tree = Rose::DB::Object::Helpers::as_tree($object, %params);
+  $self->_fix_tree($tree, $object);
+  return $tree;
+}
+
+sub to_object {
+  my ($self) = @_;
+  my $object = Rose::DB::Object::Helpers::new_from_tree("SL::DB::" . $self->type, $self->content);
+
+  # Reset primary key columns and itime/mtime if the class supports it.
+  foreach ($object->meta->primary_key, 'itime', 'mtime') {
+    $object->$_(undef) if $object->can($_);
+  }
+
+  # Let sub classes fix the objects further.
+  $self->_fix_object($object);
+  return $object;
+}
+
+sub dump {
+  my ($self, $object) = @_;
+  return $self->as_tree($self->reload_object($object), max_depth => 1);
+}
+
+sub describe {
+  die "'describe' method not overwritten by derived class";
+}
+
+sub _fix_object {
+  my ($self, $object) = @_;
+  # To be overwritten by child classes.
+}
+
+sub _fix_tree {
+  my ($self, $tree, $object) = @_;
+
+  # Delete primary key columns and itime/mtime if the class supports it.
+  foreach ($object->meta->primary_key, 'itime', 'mtime') {
+    delete $tree->{$_} if $object->can($_);
+  }
+}
+
+sub _binary_column_names {
+  my ($self, $class) = @_;
+  return map  { $_->name }
+         grep { ref($_) =~ m/Pg::Bytea$/i }
+         @{ $class->meta->columns };
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Clipboard::Base - Base class for clipboard specialization classes
+
+=head1 SYNOPSIS
+
+See the synopsis of L<SL::Clipboard>.
+
+=head1 OVERVIEW
+
+This is a base class providing a lot of utility and
+defaults. Sub-classes must overwrite at least the function
+L</describe> but can overwrite others as well.
+
+Writing a specialized sub-class for a database type involves
+overwriting one or more functions. These are:
+
+=over 4
+
+=item * C<describe>
+
+Must be overwritten. Returns a human-readable description of the
+content. Should only be one line.
+
+=item * C<dump>
+
+Optional. Overwrite if sub-class needs to dump more/less than the
+implementation in this class dumps.
+
+=item * C<_fix_object>
+
+Optional. Overwrite if re-created Rose::DB::Object instances must be
+cleaned further before they're returned to the caller.
+
+=item * C<_fix_tree>
+
+Optional. Overwrite if the tree created during a copy operation of a
+Rose::DB::Object instance must be cleaned further before it's stored.
+
+=back
+
+You don't have to or should not overwrite the other functions:
+
+=over 4
+
+=item * C<as_tree>
+
+=item * C<reload_object>
+
+=item * C<to_object>
+
+=item * C<type>
+
+=back
+
+Don't forget to C<use> the specialized module here in Base!
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<as_tree $object, %params>
+
+A convenience function calling L<Rose::DB::Object::Helpers/as_tree>
+with C<$object> and C<%params> as parameters. Returns a hash/array
+reference tree of the function.
+
+Don't overwrite this function in sub-classes. Overwrite L</dump>
+instead.
+
+=item C<describe>
+
+Returns a human-readable description of the content. This should only
+be a single line without any markup.
+
+Sub-classes must overwrite this function.
+
+=item C<dump $object>
+
+Dumps the object as a hash/array tree and returns it by calling
+L<Rose::DB::Object::Helpers/as_tree>. The default implementation
+reloads the object first by calling L</reload_object>. It also only
+dumps the object itself, not any of the relationships, by calling
+C<as_tree> with the parameter C<max_depth =E<gt> 1>.
+
+Overwrite this in a sub-class if you need to dump more or differently
+(see L<SL::Clipboard::RequirementSpecItem> for an example).
+
+=item C<reload_object $object>
+
+Reloads C<$object> from the database and returns a new instance. Can
+be useful for sanitizing the object given to L</dump> before
+converting into a tree. It is used by the default implementation of
+L</dump>.
+
+=item C<to_object>
+
+Converts the dumped representation back to a Rose::DB::Object
+instance. Several columns of the newly created object are cleared by
+C<to_object> itself: the primary key columns (if any) and the columns
+C<itime> and C<mtime> (if the object has such columns).
+
+This function should not be overwritten by sub-classes. Instead,
+functions can overwrite C<_fix_object> which can be used for sanitizing
+the newly created object before handing it back to the caller.
+
+=item C<type>
+
+Returns the actual clipped type (e.g. C<RequirementSpecItem>). This is
+derived from the actual class name of C<$self>.
+
+=item C<_binary_column_names $class>
+
+Returns an array of column names that have a binary type. Useful for
+sub-classes which need to encode binary content in Base64 during
+C<dump>.
+
+=item C<_fix_object $object>
+
+This function is called by L</to_object> before the object is passed
+back to the caller. It does not do anything in the default
+implementation, but sub-classes are free to overwrite it if they need
+to sanitize the object. See L<SL::Clipboard::RequirementSpecItem> for
+an example.
+
+Its return value is ignored.
+
+=item C<_fix_tree $tree, $object>
+
+This function is called by L</as_tree> after dumping and before the
+object is stored during a copy operation. In the default
+implementation all primary key columns and the columns C<itime> and
+C<mtime> (if the object has such columns) are removed from the tree.
+Sub-classes are free to overwrite it if they need to sanitize the
+tree. See L<SL::Clipboard::RequirementSpecItem> for an example.
+
+C<$object> is just passed in for reference and should not be modified.
+
+Its return value is ignored.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
diff --git a/SL/Controller/CsvImport/Clipboard/RequirementSpecItem.pm b/SL/Controller/CsvImport/Clipboard/RequirementSpecItem.pm
new file mode 100644 (file)
index 0000000..85bd5d9
--- /dev/null
@@ -0,0 +1,101 @@
+package SL::Clipboard::RequirementSpecItem;
+
+use strict;
+
+use parent qw(SL::Clipboard::Base);
+
+use List::Util qw(sum);
+
+use SL::Common;
+use SL::Locale::String;
+
+sub dump {
+  my ($self, $object) = @_;
+
+  return $self->as_tree(_load_children($self->reload_object($object)), exclude => sub { ref($_[0]) !~ m/::RequirementSpecItem$/ });
+}
+
+sub describe {
+  my ($self) = @_;
+
+  my $item              = $self->content;
+  my $num_children      = @{ $item->{children} || [] };
+  my $num_grandchildren = sum map { scalar(@{ $_->{children} || [] }) } @{ $item->{children} || [] };
+
+  if ($item->{item_type} eq 'section') {
+    return t8('Requirement spec section #1 "#2" with #3 function blocks and a total of #4 sub function blocks; preamble: "#5"',
+              $item->{fb_number}, $item->{title}, $num_children, $num_grandchildren, Common::truncate($item->{description}, strip => 'full'));
+  } elsif ($item->{item_type} eq 'function-block') {
+    return t8('Requirement spec function block #1 with #2 sub function blocks; description: "#3"',
+              $item->{fb_number}, $num_children, Common::truncate($item->{description}, strip => 'full'));
+  } else {
+    return t8('Requirement spec sub function block #1; description: "#2"',
+              $item->{fb_number}, Common::truncate($item->{description}, strip => 'full'));
+  }
+}
+
+sub _load_children {
+  my ($object) = @_;
+
+  _load_children($_) for @{ $object->children };
+
+  return $object;
+}
+
+sub _fix_object {
+  my ($self, $object) = @_;
+
+  $object->$_(undef)     for qw(fb_number);
+  $self->_fix_object($_) for @{ $object->children || [] };
+}
+
+sub _fix_tree {
+  my ($self, $tree, $object) = @_;
+
+  delete @{ $tree }{ qw(id itime mtime parent_id position requirement_spec_id) };
+  $self->_fix_tree($_) for @{ $tree->{children} || [] };
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Clipboard::RequirementSpecItem - Clipboard specialization for
+SL::DB::RequirementSpecItem
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<describe>
+
+Returns a human-readable description depending on the copied type
+(section, function block or sub function block).
+
+=item C<dump $object>
+
+This specialization reloads C<$object> from the database, loads all of
+its children (but only the other requirement spec items, no other
+relationships) and dumps it.
+
+=item C<_fix_object $object>
+
+Fixes C<$object> and all of its children by clearing certain columns
+like the position or function block numbers.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
diff --git a/SL/Controller/CsvImport/Clipboard/RequirementSpecPicture.pm b/SL/Controller/CsvImport/Clipboard/RequirementSpecPicture.pm
new file mode 100644 (file)
index 0000000..7a3757f
--- /dev/null
@@ -0,0 +1,84 @@
+package SL::Clipboard::RequirementSpecPicture;
+
+use strict;
+
+use parent qw(SL::Clipboard::Base);
+
+use SL::Common;
+use SL::Locale::String;
+use MIME::Base64;
+
+sub dump {
+  my ($self, $object) = @_;
+
+  $self->reload_object($object);
+
+  my $tree    = $self->as_tree($object, exclude => sub { ref($_[0]) !~ m/::RequirementSpecPicture$/ });
+  $tree->{$_} = encode_base64($tree->{$_}, '') for $self->_binary_column_names('SL::DB::RequirementSpecPicture');
+
+  return $tree;
+}
+
+sub describe {
+  my ($self) = @_;
+
+  return t8('Requirement spec picture "#1"', $self->content->{description} ? $self->content->{description} . ' (' . $self->content->{picture_file_name} . ')' : $self->content->{picture_file_name});
+}
+
+sub _fix_object {
+  my ($self, $object) = @_;
+
+  $object->$_(undef) for qw(number);
+  $object->$_(decode_base64($object->$_)) for $self->_binary_column_names('SL::DB::RequirementSpecPicture');
+
+  return $object;
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Clipboard::RequirementSpecPicture - Clipboard specialization for
+SL::DB::RequirementSpecPicture
+
+=head1 NOTES
+
+The underlying RDBO model contains binary columns, but binary data
+cannot be dumped as YAML. Therefore the binary content is encoded in
+Base64 in L</dump> and decoded back to binary form in L</_fix_object>.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<describe>
+
+Returns a human-readable description including the title and an
+excerpt of its content.
+
+=item C<dump $object>
+
+This specialization reloads C<$object> from the database, and dumps
+it. Binary columns are dumped encoded in Base64.
+
+=item C<_fix_object $object>
+
+Fixes C<$object> by clearing certain columns like the number. Also
+decodes binary columns from Base64 back to binary.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
diff --git a/SL/Controller/CsvImport/Clipboard/RequirementSpecTextBlock.pm b/SL/Controller/CsvImport/Clipboard/RequirementSpecTextBlock.pm
new file mode 100644 (file)
index 0000000..4b40a8e
--- /dev/null
@@ -0,0 +1,81 @@
+package SL::Clipboard::RequirementSpecTextBlock;
+
+use strict;
+
+use parent qw(SL::Clipboard::Base);
+
+use SL::Clipboard::RequirementSpecPicture;
+use SL::Common;
+use SL::Locale::String;
+
+sub dump {
+  my ($self, $object) = @_;
+
+  $self->reload_object($object);
+
+  my $tree          = $self->as_tree($object, exclude => sub { ref($_[0]) !~ m/::RequirementSpecTextBlock$/ });
+  $tree->{pictures} = [ map { SL::Clipboard::RequirementSpecPicture->new->dump($_) } @{ $object->pictures } ];
+
+  return $tree;
+}
+
+sub describe {
+  my ($self) = @_;
+
+  return t8('Requirement spec text block "#1"; content: "#2"', $self->content->{title}, Common::truncate($self->content->{text}, strip => 'full'));
+}
+
+sub _fix_object {
+  my ($self, $object) = @_;
+
+  $object->$_(undef) for qw(output_position position requirement_spec_id);
+
+  SL::Clipboard::RequirementSpecPicture->new->_fix_object($_) for @{ $object->pictures || [] };
+
+  return $object;
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Clipboard::RequirementSpecTextBlock - Clipboard specialization for
+SL::DB::RequirementSpecTextBlock
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<describe>
+
+Returns a human-readable description including the title and an
+excerpt of its content.
+
+=item C<dump $object>
+
+This specialization reloads C<$object> from the database, loads all of
+its pictures and dumps it. The pictures are dumped using the clipboard
+specialization for it, L<SL::Clipboard::RequirementSpecPicture/dump>.
+
+=item C<_fix_object $object>
+
+Fixes C<$object> by clearing certain columns like the position. Lets
+pictures be fixed by the clipboard specialization for it,
+L<SL::Clipboard::RequirementSpecPicture/_fix_object>.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
index 62ecb11..2e5a9e9 100644 (file)
@@ -9,6 +9,7 @@ use DateTime;
 
 use SL::Controller::CsvImport::Helper::Consistency;
 use SL::DB::DeliveryOrder;
+use SL::DB::DeliveryOrder::TypeData qw(:types);
 use SL::DB::DeliveryOrderItem;
 use SL::DB::DeliveryOrderItemsStock;
 use SL::DB::Part;
@@ -21,6 +22,7 @@ use SL::DB::Unit;
 use SL::DB::Inventory;
 use SL::DB::TransferType;
 use SL::DBUtils;
+use SL::Helper::ShippedQty;
 use SL::PriceSource;
 use SL::TransNumber;
 use SL::Util qw(trim);
@@ -214,10 +216,10 @@ sub setup_displayable_columns {
                                  { name => 'globalprojectnumber',     description => $::locale->text('Document Project (number)')             },
                                  { name => 'globalproject_id',        description => $::locale->text('Document Project (database ID)')        },
                                  { name => 'intnotes',                description => $::locale->text('Internal Notes')                        },
-                                 { name => 'is_sales',                description => $::locale->text('Is sales')                              },
                                  { name => 'language',                description => $::locale->text('Language (name)')                       },
                                  { name => 'language_id',             description => $::locale->text('Language (database ID)')                },
                                  { name => 'notes',                   description => $::locale->text('Notes')                                 },
+                                 { name => 'order_type',              description => $::locale->text('Delivery Order Type')                   },
                                  { name => 'ordnumber',               description => $::locale->text('Order Number')                          },
                                  { name => 'payment',                 description => $::locale->text('Payment terms (name)')                  },
                                  { name => 'payment_id',              description => $::locale->text('Payment terms (database ID)')           },
@@ -552,7 +554,7 @@ sub handle_order {
     push @{ $entry->{errors} }, $::locale->text('Error: Customer/vendor missing');
   }
 
-  $self->handle_is_sales($entry);
+  $self->handle_type($entry);
   $self->check_contact($entry);
   $self->check_language($entry);
   $self->check_payment($entry);
@@ -684,11 +686,19 @@ sub handle_stock {
   }
 }
 
-sub handle_is_sales {
+sub handle_type {
   my ($self, $entry) = @_;
 
-  if (!exists $entry->{raw_data}->{is_sales}) {
-    $entry->{object}->is_sales(!!$entry->{object}->customer_id);
+  if (!exists $entry->{raw_data}->{order_type}) {
+    # if no type is present - set to sales delivery order or purchase delivery
+    # order depending on is_sales or customer/vendor
+
+    $entry->{object}->order_type(
+      $entry->{object}->customer_id  ? SALES_DELIVERY_ORDER_TYPE :
+      $entry->{object}->vendor_id    ? PURCHASE_DELIVERY_ORDER_TYPE :
+      $entry->{raw_data}->{is_sales} ? SALES_DELIVERY_ORDER_TYPE :
+                                       PURCHASE_DELIVERY_ORDER_TYPE
+    );
   }
 }
 
@@ -710,6 +720,10 @@ sub handle_order_sources {
     push @{ $entry->{errors} }, $::locale->text('Error: More than one source order found');
   }
 
+  foreach my $order (@$orders) {
+    $self->{remaining_source_qtys_by_item_id} = { map { $_->id => $_->qty } @{ $order->items } };
+  }
+
   $record->{source_orders} = $orders;
 }
 
@@ -721,9 +735,38 @@ sub handle_item_source {
 
   return if !@{ $record->{source_orders} };
 
+  # Todo: units?
+
   foreach my $order (@{ $record->{source_orders} }) {
-    $item->{source_item} = first { $item->parts_id == $_->parts_id && $item->qty == $_->qty} @{ $order->items_sorted };
-    last if $item->{source_item};
+    # First: Excact matches and source order position is still complete.
+    $item->{source_item} = first {
+         $item->parts_id                                     == $_->parts_id
+      && $item->qty                                          == $_->qty
+      && $self->{remaining_source_qtys_by_item_id}->{$_->id} == $_->qty
+    } @{ $order->items_sorted };
+    if ($item->{source_item}) {
+      $self->{remaining_source_qtys_by_item_id}->{$item->{source_item}->id} -= $item->qty;
+      last;
+    }
+
+    # Second: Smallest remaining order qty greater or equal delivery order qty.
+    $item->{source_item} = first {
+         $item->parts_id                                     == $_->parts_id
+      && $self->{remaining_source_qtys_by_item_id}->{$_->id} >= $item->qty
+    } sort { $self->{remaining_source_qtys_by_item_id}->{$a->id} <=> $self->{remaining_source_qtys_by_item_id}->{$b->id} } @{ $order->items_sorted };
+    if ($item->{source_item}) {
+      $self->{remaining_source_qtys_by_item_id}->{$item->{source_item}->id} -= $item->qty;
+      last;
+    }
+
+    # Last: Overdelivery?
+    # $item->{source_item} = first {
+    #      $item->parts_id == $_->parts_id
+    # } @{ $order->items_sorted };
+    # if ($item->{source_item}) {
+    #   $self->{remaining_source_qtys_by_item_id}->{$item->{source_item}->id} -= $item->qty;
+    #   last;
+    # }
   }
 }
 
@@ -1112,18 +1155,8 @@ sub save_additions {
 
   # delivery order for all positions created?
   if (scalar(@$orders)) {
-    foreach my $order (@{ $orders }) {
-      my $all_deliverd;
-      foreach my $orderitem (@{ $order->items }) {
-        my $delivered_qty = 0;
-        foreach my $do_item (@{$orderitem->linked_records(to => 'DeliveryOrderItem')}) {
-          $delivered_qty += $do_item->unit_obj->convert_to($do_item->qty, $orderitem->unit_obj);
-        }
-        $all_deliverd = $orderitem->qty <= $delivered_qty;
-        last if !$all_deliverd;
-      }
-      $order->update_attributes(delivered => !!$all_deliverd);
-    }
+    SL::Helper::ShippedQty->new->calculate($orders)->write_to_objects;
+    $_->update_attributes(delivered => $_->delivered) for @{ $orders };
   }
 
   # inventory (or use WH->transfer?)
index d1ce92b..5538a73 100644 (file)
@@ -208,7 +208,7 @@ sub handle_salesman {
     if ($vc_obj && $vc_obj->salesman_id) {
       $object->salesman(SL::DB::Manager::Employee->find_by(id => $vc_obj->salesman_id));
     } else {
-      $object->salesman(SL::DB::Manager::Employee->find_by(login => $::myconfig{login}));
+      $object->salesman(SL::DB::Manager::Employee->current);
     }
   }
 }
index c724fb8..e6f6794 100644 (file)
@@ -53,7 +53,8 @@ sub init_parts_by {
   my ($self) = @_;
 
   my $all_parts = SL::DB::Manager::Part->get_all;
-  return { map { my $col = $_; ( $col => { map { ( $_->$col => $_ ) } @{ $all_parts } } ) } qw(id partnumber ean description) };
+  return { map { my $col = $_; ( $col =>
+         { map { ( $_->$col => $_ ) } grep { defined $_->$col } @{ $all_parts } } ) } qw(id partnumber ean description) };
 }
 
 sub init_warehouses_by {
@@ -70,7 +71,6 @@ sub init_bins_by {
   my $bins_by;
   $bins_by->{_wh_id_and_id_ident()}          = { map { ( _wh_id_and_id_maker($_->warehouse_id, $_->id)                   => $_ ) } @{ $all_bins } };
   $bins_by->{_wh_id_and_description_ident()} = { map { ( _wh_id_and_description_maker($_->warehouse_id, $_->description) => $_ ) } @{ $all_bins } };
-
   return $bins_by;
 }
 
@@ -127,6 +127,8 @@ sub check_warehouse {
 
   my $object = $entry->{object};
 
+  $self->settings->{apply_warehouse} ||= '';  # avoid warnings if undefined
+
   # If warehouse from front-end is enforced for all transfers, use this, if valid.
   if ($self->settings->{apply_warehouse} eq 'all') {
     $object->warehouse_id(undef);
@@ -185,6 +187,8 @@ sub check_bin {
 
   my $object = $entry->{object};
 
+  $self->settings->{apply_bin} ||= '';  # avoid warnings if undefined
+
   # If bin from front-end is enforced for all transfers, use this, if valid.
   if ($self->settings->{apply_bin} eq 'all') {
     $object->bin_id(undef);
@@ -217,7 +221,7 @@ sub check_bin {
   }
 
   # Map description to ID if given.
-  if (!$object->bin_id && $entry->{raw_data}->{bin}) {
+  if (!$object->bin_id && $entry->{raw_data}->{bin} && $object->warehouse_id) {
     my $bin = $self->bins_by->{_wh_id_and_description_ident()}->{ _wh_id_and_description_maker($object->warehouse_id, $entry->{raw_data}->{bin}) };
     if (!$bin) {
       push @{ $entry->{errors} }, $::locale->text('Error: Invalid bin');
@@ -272,11 +276,20 @@ sub check_part {
 # This imports inventories when target_qty is given, transfers else.
 # So we get the actual qty in stock and transfer the difference in case of
 # a given target_qty
-sub check_qty{
+sub check_qty {
   my ($self, $entry) = @_;
 
   my $object = $entry->{object};
 
+  # parse qty (may be float values)
+  if (exists $entry->{raw_data}->{target_qty}) {
+    $entry->{raw_data}->{target_qty} = $::form->parse_amount(\%::myconfig, $entry->{raw_data}->{target_qty});
+    # $object->target_qty($entry->{raw_data}->{target_qty});
+  }
+  if (exists $entry->{raw_data}->{qty}) {
+    $entry->{raw_data}->{qty}        = $::form->parse_amount(\%::myconfig, $entry->{raw_data}->{qty});
+    $object->qty($entry->{raw_data}->{qty});
+  }
   if (! exists $entry->{raw_data}->{target_qty} && ! exists $entry->{raw_data}->{qty}) {
     push @{ $entry->{errors} }, $::locale->text('Error: A quantity or a target quantity must be given.');
     return 0;
@@ -370,7 +383,7 @@ sub handle_employee {
 
   # employee from login if not given
   if (!$object->employee_id) {
-    $object->employee_id(SL::DB::Manager::Employee->find_by(login => $::myconfig{login})->id);
+    $object->employee_id(SL::DB::Manager::Employee->current->id) if SL::DB::Manager::Employee->current;
   }
 
   if ($object->employee_id) {
index 0b124e9..193523a 100644 (file)
@@ -25,6 +25,7 @@ __PACKAGE__->run_before('load_config', only => [ qw(edit update destroy) ]);
 our %translations = (
   text      => t8('Free-form text'),
   textfield => t8('Text field'),
+  htmlfield => t8('HTML field'),
   number    => t8('Number'),
   date      => t8('Date'),
   timestamp => t8('Timestamp'),
@@ -35,7 +36,7 @@ our %translations = (
   part      => t8('Part'),
 );
 
-our @types = qw(text textfield number date bool select customer vendor part); # timestamp
+our @types = qw(text textfield htmlfield number date bool select customer vendor part); # timestamp
 
 #
 # actions
index 5470284..f9e2515 100644 (file)
@@ -61,6 +61,7 @@ __PACKAGE__->run_before(
     'delete',
     'delete_contact',
     'delete_shipto',
+    'delete_additional_billing_address',
   ]
 );
 
@@ -71,6 +72,7 @@ __PACKAGE__->run_before(
     'show',
     'update',
     'ajaj_get_shipto',
+    'ajaj_get_additional_billing_address',
     'ajaj_get_contact',
     'ajax_list_prices',
   ]
@@ -88,6 +90,7 @@ __PACKAGE__->run_before(
 
 __PACKAGE__->run_before('normalize_name');
 
+my @ADDITIONAL_BILLING_ADDRESS_COLUMNS = qw(name department_1 department_2 contact street zipcode city country gln email phone fax default_address);
 
 sub action_add {
   my ($self) = @_;
@@ -280,6 +283,21 @@ sub _save {
       $self->{shipto}->save(cascade => 1);
     }
 
+    if ($self->is_customer && any { $self->{additional_billing_address}->$_ ne '' } grep { $_ ne 'default_address' } @ADDITIONAL_BILLING_ADDRESS_COLUMNS) {
+      $self->{additional_billing_address}->customer_id($self->{cv}->id);
+      $self->{additional_billing_address}->save(cascade => 1);
+
+      # Make sure only one address per customer has "default address" set.
+      if ($self->{additional_billing_address}->default_address) {
+        SL::DB::Manager::AdditionalBillingAddress->update_all(
+          set   => { default_address => 0, },
+          where => [
+            customer_id => $self->{cv}->id,
+            '!id'       => $self->{additional_billing_address}->id,
+          ]);
+      }
+    }
+
     my $snumbers = $self->is_vendor() ? 'vendornumber_'. $self->{cv}->vendornumber : 'customernumber_'. $self->{cv}->customernumber;
     SL::DB::History->new(
       trans_id => $self->{cv}->id,
@@ -325,6 +343,10 @@ sub action_save {
     push(@redirect_params, shipto_id => $self->{shipto}->shipto_id);
   }
 
+  if ( $self->is_customer && $self->{additional_billing_address}->id ) {
+    push(@redirect_params, additional_billing_address_id => $self->{additional_billing_address}->id);
+  }
+
   $self->redirect_to(@redirect_params);
 }
 
@@ -512,6 +534,32 @@ sub action_delete_shipto {
   $self->action_edit();
 }
 
+sub action_delete_additional_billing_address {
+  my ($self) = @_;
+
+  my $db = $self->{additional_billing_address}->db;
+
+  if ( !$self->{additional_billing_address}->id ) {
+    SL::Helper::Flash::flash('error', $::locale->text('No address selected to delete'));
+  } else {
+    $db->with_transaction(sub {
+      if ( $self->{additional_billing_address}->used ) {
+        $self->{additional_billing_address}->detach;
+        $self->{additional_billing_address}->save(cascade => 1);
+        SL::Helper::Flash::flash('info', $::locale->text('Address is in use and was flagged invalid.'));
+      } else {
+        $self->{additional_billing_address}->delete(cascade => 1);
+        SL::Helper::Flash::flash('info', $::locale->text('Address deleted.'));
+      }
+
+      1;
+    }) || die($db->error);
+
+    $self->{additional_billing_address} = SL::DB::AdditionalBillingAddress->new;
+  }
+
+  $self->action_edit;
+}
 
 sub action_search {
   my ($self) = @_;
@@ -637,6 +685,18 @@ sub action_ajaj_get_shipto {
   $self->render(\SL::JSON::to_json($data), { type => 'json', process => 0 });
 }
 
+sub action_ajaj_get_additional_billing_address {
+  my ($self) = @_;
+
+  my $data = {
+    additional_billing_address => {
+      map { ($_ => $self->{additional_billing_address}->$_) } ('id', @ADDITIONAL_BILLING_ADDRESS_COLUMNS)
+    },
+  };
+
+  $self->render(\SL::JSON::to_json($data), { type => 'json', process => 0 });
+}
+
 sub action_ajaj_get_contact {
   my ($self) = @_;
 
@@ -899,6 +959,15 @@ sub _instantiate_args {
   $self->{shipto}->assign_attributes(%{$::form->{shipto}});
   $self->{shipto}->module('CT');
 
+  if ($self->is_customer) {
+    if ( $::form->{additional_billing_address}->{id} ) {
+      $self->{additional_billing_address} = SL::DB::AdditionalBillingAddress->new(id => $::form->{additional_billing_address}->{id})->load;
+    } else {
+      $self->{additional_billing_address} = SL::DB::AdditionalBillingAddress->new;
+    }
+    $self->{additional_billing_address}->assign_attributes(%{ $::form->{additional_billing_address} });
+  }
+
   if ( $::form->{contact}->{cp_id} ) {
     $self->{contact} = SL::DB::Contact->new(cp_id => $::form->{contact}->{cp_id})->load();
   } else {
@@ -940,6 +1009,16 @@ sub _load_customer_vendor {
     $self->{shipto} = SL::DB::Shipto->new();
   }
 
+  if ($self->is_customer) {
+    if ( $::form->{additional_billing_address_id} ) {
+      $self->{additional_billing_address} = SL::DB::AdditionalBillingAddress->new(id => $::form->{additional_billing_address_id})->load;
+      die($::locale->text('Error')) if $self->{additional_billing_address}->customer_id != $self->{cv}->id;
+
+    } else {
+      $self->{additional_billing_address} = SL::DB::AdditionalBillingAddress->new;
+    }
+  }
+
   if ( $::form->{contact_id} ) {
     $self->{contact} = SL::DB::Contact->new(cp_id => $::form->{contact_id})->load();
 
@@ -988,6 +1067,7 @@ sub _create_customer_vendor {
   $self->{note_followup} = SL::DB::FollowUp->new();
 
   $self->{shipto} = SL::DB::Shipto->new();
+  $self->{additional_billing_address} = SL::DB::AdditionalBillingAddress->new if $self->is_customer;
 
   $self->{contact} = $self->_new_contact_object;
 }
@@ -1064,6 +1144,11 @@ sub _pre_render {
   $self->{shiptos} = $self->{cv}->shipto;
   $self->{shiptos} ||= [];
 
+  if ($self->is_customer) {
+    $self->{additional_billing_addresses} = $self->{cv}->additional_billing_addresses;
+    $self->{additional_billing_addresses} ||= [];
+  }
+
   $self->{notes} = SL::DB::Manager::Note->get_all(
     query => [
       trans_id => $self->{cv}->id,
@@ -1120,9 +1205,7 @@ sub _pre_render {
 
   $self->{template_args} ||= {};
 
-  $::request->{layout}->add_javascripts('kivi.CustomerVendor.js');
-  $::request->{layout}->add_javascripts('kivi.File.js');
-  $::request->{layout}->add_javascripts('kivi.CustomerVendorTurnover.js');
+  $::request->{layout}->add_javascripts("$_.js") for qw (kivi.CustomerVendor kivi.File kivi.CustomerVendorTurnover ckeditor/ckeditor ckeditor/adapters/jquery);
 
   $self->_setup_form_action_bar;
 }
@@ -1311,11 +1394,15 @@ sub _new_customer_vendor_object {
   my ($self) = @_;
 
   my $class  = 'SL::DB::' . ($self->is_vendor ? 'Vendor' : 'Customer');
-  return $class->new(
+  my $object = $class->new(
     contacts         => [],
     shipto           => [],
     custom_variables => [],
   );
+
+  $object->additional_billing_addresses([]) if $self->is_customer;
+
+  return $object;
 }
 
 sub _new_contact_object {
diff --git a/SL/Controller/DeliveryOrder.pm b/SL/Controller/DeliveryOrder.pm
new file mode 100644 (file)
index 0000000..7c4a99b
--- /dev/null
@@ -0,0 +1,2419 @@
+package SL::Controller::DeliveryOrder;
+
+use strict;
+use parent qw(SL::Controller::Base);
+
+use SL::Helper::Flash qw(flash_later);
+use SL::Helper::Number qw(_format_number _parse_number);
+use SL::Presenter::Tag qw(select_tag hidden_tag div_tag);
+use SL::Presenter::DeliveryOrder qw(delivery_order_status_line);
+use SL::Locale::String qw(t8);
+use SL::SessionFile::Random;
+use SL::PriceSource;
+use SL::Webdav;
+use SL::File;
+use SL::MIME;
+use SL::Util qw(trim);
+use SL::YAML;
+use SL::DB::History;
+use SL::DB::Order;
+use SL::DB::Default;
+use SL::DB::Unit;
+use SL::DB::Order;
+use SL::DB::Part;
+use SL::DB::PartClassification;
+use SL::DB::PartsGroup;
+use SL::DB::Printer;
+use SL::DB::Language;
+use SL::DB::RecordLink;
+use SL::DB::Shipto;
+use SL::DB::Translation;
+use SL::DB::TransferType;
+
+use SL::Helper::CreatePDF qw(:all);
+use SL::Helper::PrintOptions;
+use SL::Helper::ShippedQty;
+use SL::Helper::UserPreferences::DisplayPreferences;
+use SL::Helper::UserPreferences::PositionsScrollbar;
+use SL::Helper::UserPreferences::UpdatePositions;
+
+use SL::Controller::Helper::GetModels;
+use SL::Controller::DeliveryOrder::TypeData qw(:types);
+
+use List::Util qw(first sum0);
+use List::UtilsBy qw(sort_by uniq_by);
+use List::MoreUtils qw(any none pairwise first_index);
+use English qw(-no_match_vars);
+use File::Spec;
+use Cwd;
+use Sort::Naturally;
+
+use Rose::Object::MakeMethods::Generic
+(
+ scalar => [ qw(item_ids_to_delete is_custom_shipto_to_delete) ],
+ 'scalar --get_set_init' => [ qw(order valid_types type cv p all_price_factors search_cvpartnumber show_update_button part_picker_classification_ids type_data) ],
+);
+
+
+# safety
+__PACKAGE__->run_before('check_auth',
+                        except => [ qw(update_stock_information) ]);
+
+__PACKAGE__->run_before('check_auth_for_edit',
+                        except => [ qw(update_stock_information edit show_customer_vendor_details_dialog price_popup stock_in_out_dialog load_second_rows) ]);
+
+__PACKAGE__->run_before('get_unalterable_data',
+                        only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_ap_transaction
+                                     print send_email) ]);
+
+#
+# actions
+#
+
+# add a new order
+sub action_add {
+  my ($self) = @_;
+
+  $self->order->transdate(DateTime->now_local());
+  $self->type_data->set_reqdate_by_type;
+
+
+  $self->pre_render();
+  $self->render(
+    'delivery_order/form',
+    title => $self->get_title_for('add'),
+    %{$self->{template_args}}
+  );
+}
+
+sub action_add_from_order {
+  my ($self) = @_;
+  # this interfers with init_order
+  $self->{converted_from_oe_id} = delete $::form->{id};
+
+  $self->type_data->validate($::form->{type});
+
+  my $order = SL::DB::Order->new(id => $self->{converted_from_oe_id})->load;
+
+  $self->order(SL::DB::DeliveryOrder->new_from($order, type => $::form->{type}));
+
+  $self->action_add;
+}
+
+# edit an existing order
+sub action_edit {
+  my ($self) = @_;
+
+  if ($::form->{id}) {
+    $self->load_order;
+
+  } else {
+    # this is to edit an order from an unsaved order object
+
+    # set item ids to new fake id, to identify them as new items
+    foreach my $item (@{$self->order->items_sorted}) {
+      $item->{new_fake_id} = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
+    }
+    # trigger rendering values for second row as hidden, because they
+    # are loaded only on demand. So we need to keep the values from
+    # the source.
+    $_->{render_second_row} = 1 for @{ $self->order->items_sorted };
+  }
+
+  $self->pre_render();
+  $self->render(
+    'delivery_order/form',
+    title => $self->get_title_for('edit'),
+    %{$self->{template_args}}
+  );
+}
+
+# edit a collective order (consisting of one or more existing orders)
+sub action_edit_collective {
+  my ($self) = @_;
+
+  # collect order ids
+  my @multi_ids = map {
+    $_ =~ m{^multi_id_(\d+)$} && $::form->{'multi_id_' . $1} && $::form->{'trans_id_' . $1} && $::form->{'trans_id_' . $1}
+  } grep { $_ =~ m{^multi_id_\d+$} } keys %$::form;
+
+  # fall back to add if no ids are given
+  if (scalar @multi_ids == 0) {
+    $self->action_add();
+    return;
+  }
+
+  # fall back to save as new if only one id is given
+  if (scalar @multi_ids == 1) {
+    $self->order(SL::DB::DeliveryOrder->new(id => $multi_ids[0])->load);
+    $self->action_save_as_new();
+    return;
+  }
+
+  # make new order from given orders
+  my @multi_orders = map { SL::DB::DeliveryOrder->new(id => $_)->load } @multi_ids;
+  $self->{converted_from_oe_id} = join ' ', map { $_->id } @multi_orders;
+  $self->order(SL::DB::DeliveryOrder->new_from_multi(\@multi_orders, sort_sources_by => 'transdate'));
+
+  $self->action_edit();
+}
+
+# delete the order
+sub action_delete {
+  my ($self) = @_;
+
+  my $errors = $self->delete();
+
+  if (scalar @{ $errors }) {
+    $self->js->flash('error', $_) foreach @{ $errors };
+    return $self->js->render();
+  }
+
+  flash_later('info', $self->type_data->text("delete"));
+
+  my @redirect_params = (
+    action => 'add',
+    type   => $self->type,
+  );
+
+  $self->redirect_to(@redirect_params);
+}
+
+# save the order
+sub action_save {
+  my ($self) = @_;
+
+  my $errors = $self->save();
+
+  if (scalar @{ $errors }) {
+    $self->js->flash('error', $_) foreach @{ $errors };
+    return $self->js->render();
+  }
+
+  flash_later('info', $self->type_data->text("saved"));
+
+  my @redirect_params = (
+    action => 'edit',
+    type   => $self->type,
+    id     => $self->order->id,
+  );
+
+  $self->redirect_to(@redirect_params);
+}
+
+# save the order as new document an open it for edit
+sub action_save_as_new {
+  my ($self) = @_;
+
+  my $order = $self->order;
+
+  if (!$order->id) {
+    $self->js->flash('error', t8('This object has not been saved yet.'));
+    return $self->js->render();
+  }
+
+  # load order from db to check if values changed
+  my $saved_order = SL::DB::DeliveryOrder->new(id => $order->id)->load;
+
+  my %new_attrs;
+  # Lets assign a new number if the user hasn't changed the previous one.
+  # If it has been changed manually then use it as-is.
+  $new_attrs{number}    = (trim($order->number) eq $saved_order->number)
+                        ? ''
+                        : trim($order->number);
+
+  # Clear transdate unless changed
+  $new_attrs{transdate} = ($order->transdate == $saved_order->transdate)
+                        ? DateTime->today_local
+                        : $order->transdate;
+
+  # Set new reqdate unless changed if it is enabled in client config
+  $new_attrs{reqdate} = $self->type_data->get_reqdate_by_type($order->reqdate, $saved_order->reqdate);
+
+  # Update employee
+  $new_attrs{employee}  = SL::DB::Manager::Employee->current;
+
+  # Create new record from current one
+  $self->order(SL::DB::DeliveryOrder->new_from($order, destination_type => $order->type, attributes => \%new_attrs));
+
+  # no linked records on save as new
+  delete $::form->{$_} for qw(converted_from_oe_id converted_from_orderitems_ids);
+
+  # save
+  $self->action_save();
+}
+
+# print the order
+#
+# This is called if "print" is pressed in the print dialog.
+# If PDF creation was requested and succeeded, the pdf is offered for download
+# via send_file (which uses ajax in this case).
+sub action_print {
+  my ($self) = @_;
+
+  my $errors = $self->save();
+
+  if (scalar @{ $errors }) {
+    $self->js->flash('error', $_) foreach @{ $errors };
+    return $self->js->render();
+  }
+
+  $self->js_reset_order_and_item_ids_after_save;
+
+  my $format      = $::form->{print_options}->{format};
+  my $media       = $::form->{print_options}->{media};
+  my $formname    = $::form->{print_options}->{formname};
+  my $copies      = $::form->{print_options}->{copies};
+  my $groupitems  = $::form->{print_options}->{groupitems};
+  my $printer_id  = $::form->{print_options}->{printer_id};
+
+  # only pdf and opendocument by now
+  if (none { $format eq $_ } qw(pdf opendocument opendocument_pdf)) {
+    return $self->js->flash('error', t8('Format \'#1\' is not supported yet/anymore.', $format))->render;
+  }
+
+  # only screen or printer by now
+  if (none { $media eq $_ } qw(screen printer)) {
+    return $self->js->flash('error', t8('Media \'#1\' is not supported yet/anymore.', $media))->render;
+  }
+
+  # create a form for generate_attachment_filename
+  my $form   = Form->new;
+  $form->{$self->nr_key()}  = $self->order->number;
+  $form->{type}             = $self->type;
+  $form->{format}           = $format;
+  $form->{formname}         = $formname;
+  $form->{language}         = '_' . $self->order->language->template_code if $self->order->language;
+  my $pdf_filename          = $form->generate_attachment_filename();
+
+  my $pdf;
+  my @errors = generate_pdf($self->order, \$pdf, { format     => $format,
+                                                   formname   => $formname,
+                                                   language   => $self->order->language,
+                                                   printer_id => $printer_id,
+                                                   groupitems => $groupitems });
+  if (scalar @errors) {
+    return $self->js->flash('error', t8('Conversion to PDF failed: #1', $errors[0]))->render;
+  }
+
+  if ($media eq 'screen') {
+    # screen/download
+    $self->js->flash('info', t8('The PDF has been created'));
+    $self->send_file(
+      \$pdf,
+      type         => SL::MIME->mime_type_from_ext($pdf_filename),
+      name         => $pdf_filename,
+      js_no_render => 1,
+    );
+
+  } elsif ($media eq 'printer') {
+    # printer
+    my $printer_id = $::form->{print_options}->{printer_id};
+    SL::DB::Printer->new(id => $printer_id)->load->print_document(
+      copies  => $copies,
+      content => $pdf,
+    );
+
+    $self->js->flash('info', t8('The PDF has been printed'));
+  }
+
+  my @warnings = store_pdf_to_webdav_and_filemanagement($self->order, $pdf, $pdf_filename);
+  if (scalar @warnings) {
+    $self->js->flash('warning', $_) for @warnings;
+  }
+
+  $self->save_history('PRINTED');
+
+  $self->js
+    ->run('kivi.ActionBar.setEnabled', '#save_and_email_action')
+    ->render;
+}
+sub action_preview_pdf {
+  my ($self) = @_;
+
+  my $errors = $self->save();
+  if (scalar @{ $errors }) {
+    $self->js->flash('error', $_) foreach @{ $errors };
+    return $self->js->render();
+  }
+
+  $self->js_reset_order_and_item_ids_after_save;
+
+  my $format      = 'pdf';
+  my $media       = 'screen';
+  my $formname    = $self->type;
+
+  # only pdf
+  # create a form for generate_attachment_filename
+  my $form   = Form->new;
+  $form->{$self->nr_key()}  = $self->order->number;
+  $form->{type}             = $self->type;
+  $form->{format}           = $format;
+  $form->{formname}         = $formname;
+  $form->{language}         = '_' . $self->order->language->template_code if $self->order->language;
+  my $pdf_filename          = $form->generate_attachment_filename();
+
+  my $pdf;
+  my @errors = generate_pdf($self->order, \$pdf, { format     => $format,
+                                                   formname   => $formname,
+                                                   language   => $self->order->language,
+                                                 });
+  if (scalar @errors) {
+    return $self->js->flash('error', t8('Conversion to PDF failed: #1', $errors[0]))->render;
+  }
+  $self->save_history('PREVIEWED');
+  $self->js->flash('info', t8('The PDF has been previewed'));
+  # screen/download
+  $self->send_file(
+    \$pdf,
+    type         => SL::MIME->mime_type_from_ext($pdf_filename),
+    name         => $pdf_filename,
+    js_no_render => 0,
+  );
+}
+
+# open the email dialog
+sub action_save_and_show_email_dialog {
+  my ($self) = @_;
+
+  my $errors = $self->save();
+
+  if (scalar @{ $errors }) {
+    $self->js->flash('error', $_) foreach @{ $errors };
+    return $self->js->render();
+  }
+
+  my $cv_method = $self->cv;
+
+  if (!$self->order->$cv_method) {
+    return $self->js->flash('error', $self->cv eq 'customer' ? t8('Cannot send E-mail without customer given') : t8('Cannot send E-mail without vendor given'))
+                    ->render($self);
+  }
+
+  my $email_form;
+  $email_form->{to}   = $self->order->contact->cp_email if $self->order->contact;
+  $email_form->{to} ||= $self->order->$cv_method->email;
+  $email_form->{cc}   = $self->order->$cv_method->cc;
+  $email_form->{bcc}  = join ', ', grep $_, $self->order->$cv_method->bcc, SL::DB::Default->get->global_bcc;
+  # Todo: get addresses from shipto, if any
+
+  my $form = Form->new;
+  $form->{$self->nr_key()}  = $self->order->number;
+  $form->{cusordnumber}     = $self->order->cusordnumber;
+  $form->{formname}         = $self->type;
+  $form->{type}             = $self->type;
+  $form->{language}         = '_' . $self->order->language->template_code if $self->order->language;
+  $form->{language_id}      = $self->order->language->id                  if $self->order->language;
+  $form->{format}           = 'pdf';
+  $form->{cp_id}            = $self->order->contact->cp_id if $self->order->contact;
+
+  $email_form->{subject}             = $form->generate_email_subject();
+  $email_form->{attachment_filename} = $form->generate_attachment_filename();
+  $email_form->{message}             = $form->generate_email_body();
+  $email_form->{js_send_function}    = 'kivi.DeliveryOrder.send_email()';
+
+  my %files = $self->get_files_for_email_dialog();
+  $self->{all_employees} = SL::DB::Manager::Employee->get_all(query => [ deleted => 0 ]);
+  my $dialog_html = $self->render('common/_send_email_dialog', { output => 0 },
+                                  email_form  => $email_form,
+                                  show_bcc    => $::auth->assert('email_bcc', 'may fail'),
+                                  FILES       => \%files,
+                                  is_customer => $self->type_data->is_customer,
+                                  ALL_EMPLOYEES => $self->{all_employees},
+  );
+
+  $self->js
+      ->run('kivi.DeliveryOrder.show_email_dialog', $dialog_html)
+      ->reinit_widgets
+      ->render($self);
+}
+
+# send email
+#
+# Todo: handling error messages: flash is not displayed in dialog, but in the main form
+sub action_send_email {
+  my ($self) = @_;
+
+  my $errors = $self->save();
+
+  if (scalar @{ $errors }) {
+    $self->js->run('kivi.DeliveryOrder.close_email_dialog');
+    $self->js->flash('error', $_) foreach @{ $errors };
+    return $self->js->render();
+  }
+
+  $self->js_reset_order_and_item_ids_after_save;
+
+  my $email_form  = delete $::form->{email_form};
+  my %field_names = (to => 'email');
+
+  $::form->{ $field_names{$_} // $_ } = $email_form->{$_} for keys %{ $email_form };
+
+  # for Form::cleanup which may be called in Form::send_email
+  $::form->{cwd}    = getcwd();
+  $::form->{tmpdir} = $::lx_office_conf{paths}->{userspath};
+
+  $::form->{$_}     = $::form->{print_options}->{$_} for keys %{ $::form->{print_options} };
+  $::form->{media}  = 'email';
+
+  if (($::form->{attachment_policy} // '') !~ m{^(?:old_file|no_file)$}) {
+    my $pdf;
+    my @errors = generate_pdf($self->order, \$pdf, {media      => $::form->{media},
+                                                    format     => $::form->{print_options}->{format},
+                                                    formname   => $::form->{print_options}->{formname},
+                                                    language   => $self->order->language,
+                                                    printer_id => $::form->{print_options}->{printer_id},
+                                                    groupitems => $::form->{print_options}->{groupitems}});
+    if (scalar @errors) {
+      return $self->js->flash('error', t8('Conversion to PDF failed: #1', $errors[0]))->render($self);
+    }
+
+    my @warnings = store_pdf_to_webdav_and_filemanagement($self->order, $pdf, $::form->{attachment_filename});
+    if (scalar @warnings) {
+      flash_later('warning', $_) for @warnings;
+    }
+
+    my $sfile = SL::SessionFile::Random->new(mode => "w");
+    $sfile->fh->print($pdf);
+    $sfile->fh->close;
+
+    $::form->{tmpfile} = $sfile->file_name;
+    $::form->{tmpdir}  = $sfile->get_path; # for Form::cleanup which may be called in Form::send_email
+  }
+
+  $::form->{id} = $self->order->id; # this is used in SL::Mailer to create a linked record to the mail
+  $::form->send_email(\%::myconfig, 'pdf');
+
+  # internal notes unless no email journal
+  unless ($::instance_conf->get_email_journal) {
+
+    my $intnotes = $self->order->intnotes;
+    $intnotes   .= "\n\n" if $self->order->intnotes;
+    $intnotes   .= t8('[email]')                                                                                        . "\n";
+    $intnotes   .= t8('Date')       . ": " . $::locale->format_date_object(DateTime->now_local, precision => 'seconds') . "\n";
+    $intnotes   .= t8('To (email)') . ": " . $::form->{email}                                                           . "\n";
+    $intnotes   .= t8('Cc')         . ": " . $::form->{cc}                                                              . "\n"    if $::form->{cc};
+    $intnotes   .= t8('Bcc')        . ": " . $::form->{bcc}                                                             . "\n"    if $::form->{bcc};
+    $intnotes   .= t8('Subject')    . ": " . $::form->{subject}                                                         . "\n\n";
+    $intnotes   .= t8('Message')    . ": " . $::form->{message};
+
+    $self->order->update_attributes(intnotes => $intnotes);
+  }
+
+  $self->save_history('MAILED');
+
+  flash_later('info', t8('The email has been sent.'));
+
+  my @redirect_params = (
+    action => 'edit',
+    type   => $self->type,
+    id     => $self->order->id,
+  );
+
+  $self->redirect_to(@redirect_params);
+}
+
+# save the order and redirect to the frontend subroutine for a new
+# delivery order
+sub action_save_and_delivery_order {
+  my ($self) = @_;
+
+  $self->save_and_redirect_to(
+    controller => 'oe.pl',
+    action     => 'oe_delivery_order_from_order',
+  );
+}
+
+# save the order and redirect to the frontend subroutine for a new
+# invoice
+sub action_save_and_invoice {
+  my ($self) = @_;
+
+  $self->save_and_redirect_to(
+    controller => 'oe.pl',
+    action     => 'oe_invoice_from_order',
+  );
+}
+
+# workflow from sales order to sales quotation
+sub action_sales_quotation {
+  $_[0]->workflow_sales_or_request_for_quotation();
+}
+
+# workflow from sales order to sales quotation
+sub action_request_for_quotation {
+  $_[0]->workflow_sales_or_request_for_quotation();
+}
+
+# workflow from sales quotation to sales order
+sub action_sales_order {
+  $_[0]->workflow_sales_or_purchase_order();
+}
+
+# workflow from rfq to purchase order
+sub action_purchase_order {
+  $_[0]->workflow_sales_or_purchase_order();
+}
+
+# workflow from purchase order to ap transaction
+sub action_save_and_ap_transaction {
+  my ($self) = @_;
+
+  $self->save_and_redirect_to(
+    controller => 'ap.pl',
+    action     => 'add_from_purchase_order',
+  );
+}
+
+# set form elements in respect to a changed customer or vendor
+#
+# This action is called on an change of the customer/vendor picker.
+sub action_customer_vendor_changed {
+  my ($self) = @_;
+
+  setup_order_from_cv($self->order);
+
+  my $cv_method = $self->cv;
+
+  if ($self->order->$cv_method->contacts && scalar @{ $self->order->$cv_method->contacts } > 0) {
+    $self->js->show('#cp_row');
+  } else {
+    $self->js->hide('#cp_row');
+  }
+
+  if ($self->order->$cv_method->shipto && scalar @{ $self->order->$cv_method->shipto } > 0) {
+    $self->js->show('#shipto_selection');
+  } else {
+    $self->js->hide('#shipto_selection');
+  }
+
+  $self->js->val( '#order_salesman_id',      $self->order->salesman_id)        if $self->order->is_sales;
+
+  $self->js
+    ->replaceWith('#order_cp_id',            $self->build_contact_select)
+    ->replaceWith('#order_shipto_id',        $self->build_shipto_select)
+    ->replaceWith('#shipto_inputs  ',        $self->build_shipto_inputs)
+    ->replaceWith('#business_info_row',      $self->build_business_info_row)
+    ->val(        '#order_taxzone_id',       $self->order->taxzone_id)
+    ->val(        '#order_taxincluded',      $self->order->taxincluded)
+    ->val(        '#order_currency_id',      $self->order->currency_id)
+    ->val(        '#order_payment_id',       $self->order->payment_id)
+    ->val(        '#order_delivery_term_id', $self->order->delivery_term_id)
+    ->val(        '#order_intnotes',         $self->order->intnotes)
+    ->val(        '#order_language_id',      $self->order->$cv_method->language_id)
+    ->focus(      '#order_' . $self->cv . '_id')
+    ->run('kivi.DeliveryOrder.update_exchangerate');
+
+  $self->js_redisplay_cvpartnumbers;
+  $self->js->render();
+}
+
+# open the dialog for customer/vendor details
+sub action_show_customer_vendor_details_dialog {
+  my ($self) = @_;
+
+  my $is_customer = 'customer' eq $::form->{vc};
+  my $cv;
+  if ($is_customer) {
+    $cv = SL::DB::Customer->new(id => $::form->{vc_id})->load;
+  } else {
+    $cv = SL::DB::Vendor->new(id => $::form->{vc_id})->load;
+  }
+
+  my %details = map { $_ => $cv->$_ } @{$cv->meta->columns};
+  $details{discount_as_percent} = $cv->discount_as_percent;
+  $details{creditlimt}          = $cv->creditlimit_as_number;
+  $details{business}            = $cv->business->description      if $cv->business;
+  $details{language}            = $cv->language_obj->description  if $cv->language_obj;
+  $details{delivery_terms}      = $cv->delivery_term->description if $cv->delivery_term;
+  $details{payment_terms}       = $cv->payment->description       if $cv->payment;
+  $details{pricegroup}          = $cv->pricegroup->pricegroup     if $is_customer && $cv->pricegroup;
+
+  foreach my $entry (@{ $cv->shipto }) {
+    push @{ $details{SHIPTO} },   { map { $_ => $entry->$_ } @{$entry->meta->columns} };
+  }
+  foreach my $entry (@{ $cv->contacts }) {
+    push @{ $details{CONTACTS} }, { map { $_ => $entry->$_ } @{$entry->meta->columns} };
+  }
+
+  $_[0]->render('common/show_vc_details', { layout => 0 },
+                is_customer => $is_customer,
+                %details);
+
+}
+
+# called if a unit in an existing item row is changed
+sub action_unit_changed {
+  my ($self) = @_;
+
+  my $idx  = first_index { $_ eq $::form->{item_id} } @{ $::form->{orderitem_ids} };
+  my $item = $self->order->items_sorted->[$idx];
+
+  my $old_unit_obj = SL::DB::Unit->new(name => $::form->{old_unit})->load;
+  $item->sellprice($item->unit_obj->convert_to($item->sellprice, $old_unit_obj));
+
+  $self->js
+    ->run('kivi.DeliveryOrder.update_sellprice', $::form->{item_id}, $item->sellprice_as_number);
+  $self->js_redisplay_line_values;
+  $self->js->render();
+}
+
+# add an item row for a new item entered in the input row
+sub action_add_item {
+  my ($self) = @_;
+
+  delete $::form->{add_item}->{create_part_type};
+
+  my $form_attr = $::form->{add_item};
+
+  return unless $form_attr->{parts_id};
+
+  my $item = new_item($self->order, $form_attr);
+
+  $self->order->add_items($item);
+
+  $self->get_item_cvpartnumber($item);
+
+  my $item_id = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
+  my $row_as_html = $self->p->render('delivery_order/tabs/_row',
+                                     ITEM => $item,
+                                     ID   => $item_id,
+                                     SELF => $self,
+                                     in_out => $self->type_data->transfer,
+  );
+
+  if ($::form->{insert_before_item_id}) {
+    $self->js
+      ->before ('.row_entry:has(#item_' . $::form->{insert_before_item_id} . ')', $row_as_html);
+  } else {
+    $self->js
+      ->append('#row_table_id', $row_as_html);
+  }
+
+  if ( $item->part->is_assortment ) {
+    $form_attr->{qty_as_number} = 1 unless $form_attr->{qty_as_number};
+    foreach my $assortment_item ( @{$item->part->assortment_items} ) {
+      my $attr = { parts_id => $assortment_item->parts_id,
+                   qty      => $assortment_item->qty * $::form->parse_amount(\%::myconfig, $form_attr->{qty_as_number}), # TODO $form_attr->{unit}
+                   unit     => $assortment_item->unit,
+                   description => $assortment_item->part->description,
+                 };
+      my $item = new_item($self->order, $attr);
+
+      # set discount to 100% if item isn't supposed to be charged, overwriting any customer discount
+      $item->discount(1) unless $assortment_item->charge;
+
+      $self->order->add_items( $item );
+      $self->get_item_cvpartnumber($item);
+      my $item_id = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
+      my $row_as_html = $self->p->render('delivery_order/tabs/_row',
+                                         ITEM => $item,
+                                         ID   => $item_id,
+                                         SELF => $self,
+      );
+      if ($::form->{insert_before_item_id}) {
+        $self->js
+          ->before ('.row_entry:has(#item_' . $::form->{insert_before_item_id} . ')', $row_as_html);
+      } else {
+        $self->js
+          ->append('#row_table_id', $row_as_html);
+      }
+    };
+  };
+
+  $self->js
+    ->val('.add_item_input', '')
+    ->run('kivi.DeliveryOrder.init_row_handlers')
+    ->run('kivi.DeliveryOrder.renumber_positions')
+    ->focus('#add_item_parts_id_name');
+
+  $self->js->run('kivi.DeliveryOrder.row_table_scroll_down') if !$::form->{insert_before_item_id};
+
+  $self->js->render();
+}
+
+# add item rows for multiple items at once
+sub action_add_multi_items {
+  my ($self) = @_;
+
+  my @form_attr = grep { $_->{qty_as_number} } @{ $::form->{add_items} };
+  return $self->js->render() unless scalar @form_attr;
+
+  my @items;
+  foreach my $attr (@form_attr) {
+    my $item = new_item($self->order, $attr);
+    push @items, $item;
+    if ( $item->part->is_assortment ) {
+      foreach my $assortment_item ( @{$item->part->assortment_items} ) {
+        my $attr = { parts_id => $assortment_item->parts_id,
+                     qty      => $assortment_item->qty * $item->qty, # TODO $form_attr->{unit}
+                     unit     => $assortment_item->unit,
+                     description => $assortment_item->part->description,
+                   };
+        my $item = new_item($self->order, $attr);
+
+        # set discount to 100% if item isn't supposed to be charged, overwriting any customer discount
+        $item->discount(1) unless $assortment_item->charge;
+        push @items, $item;
+      }
+    }
+  }
+  $self->order->add_items(@items);
+
+  foreach my $item (@items) {
+    $self->get_item_cvpartnumber($item);
+    my $item_id = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
+    my $row_as_html = $self->p->render('delivery_order/tabs/_row',
+                                       ITEM => $item,
+                                       ID   => $item_id,
+                                       SELF => $self,
+                                       in_out => $self->type_data->transfer,
+    );
+
+    if ($::form->{insert_before_item_id}) {
+      $self->js
+        ->before ('.row_entry:has(#item_' . $::form->{insert_before_item_id} . ')', $row_as_html);
+    } else {
+      $self->js
+        ->append('#row_table_id', $row_as_html);
+    }
+  }
+
+  $self->js
+    ->run('kivi.Part.close_picker_dialogs')
+    ->run('kivi.DeliveryOrder.init_row_handlers')
+    ->run('kivi.DeliveryOrder.renumber_positions')
+    ->focus('#add_item_parts_id_name');
+
+  $self->js->run('kivi.DeliveryOrder.row_table_scroll_down') if !$::form->{insert_before_item_id};
+
+  $self->js->render();
+}
+
+sub action_update_exchangerate {
+  my ($self) = @_;
+
+  my $data = {
+    is_standard   => $self->order->currency_id == $::instance_conf->get_currency_id,
+    currency_name => $self->order->currency->name,
+  };
+
+  $self->render(\SL::JSON::to_json($data), { type => 'json', process => 0 });
+}
+
+# redisplay item rows if they are sorted by an attribute
+sub action_reorder_items {
+  my ($self) = @_;
+
+  my %sort_keys = (
+    partnumber   => sub { $_[0]->part->partnumber },
+    description  => sub { $_[0]->description },
+    qty          => sub { $_[0]->qty },
+    sellprice    => sub { $_[0]->sellprice },
+    discount     => sub { $_[0]->discount },
+    cvpartnumber => sub { $_[0]->{cvpartnumber} },
+  );
+
+  $self->get_item_cvpartnumber($_) for @{$self->order->items_sorted};
+
+  my $method = $sort_keys{$::form->{order_by}};
+  my @to_sort = map { { old_pos => $_->position, order_by => $method->($_) } } @{ $self->order->items_sorted };
+  if ($::form->{sort_dir}) {
+    if ( $::form->{order_by} =~ m/qty|sellprice|discount/ ){
+      @to_sort = sort { $a->{order_by} <=> $b->{order_by} } @to_sort;
+    } else {
+      @to_sort = sort { $a->{order_by} cmp $b->{order_by} } @to_sort;
+    }
+  } else {
+    if ( $::form->{order_by} =~ m/qty|sellprice|discount/ ){
+      @to_sort = sort { $b->{order_by} <=> $a->{order_by} } @to_sort;
+    } else {
+      @to_sort = sort { $b->{order_by} cmp $a->{order_by} } @to_sort;
+    }
+  }
+  $self->js
+    ->run('kivi.DeliveryOrder.redisplay_items', \@to_sort)
+    ->render;
+}
+
+# show the popup to choose a price/discount source
+sub action_price_popup {
+  my ($self) = @_;
+
+  my $idx  = first_index { $_ eq $::form->{item_id} } @{ $::form->{orderitem_ids} };
+  my $item = $self->order->items_sorted->[$idx];
+
+  $self->render_price_dialog($item);
+}
+
+# save the order in a session variable and redirect to the part controller
+sub action_create_part {
+  my ($self) = @_;
+
+  my $previousform = $::auth->save_form_in_session(non_scalars => 1);
+
+  my $callback     = $self->url_for(
+    action       => 'return_from_create_part',
+    type         => $self->type, # type is needed for check_auth on return
+    previousform => $previousform,
+  );
+
+  flash_later('info', t8('You are adding a new part while you are editing another document. You will be redirected to your document when saving the new part or aborting this form.'));
+
+  my @redirect_params = (
+    controller    => 'Part',
+    action        => 'add',
+    part_type     => $::form->{add_item}->{create_part_type},
+    callback      => $callback,
+    inline_create => 1,
+  );
+
+  $self->redirect_to(@redirect_params);
+}
+
+sub action_return_from_create_part {
+  my ($self) = @_;
+
+  $self->{created_part} = SL::DB::Part->new(id => delete $::form->{new_parts_id})->load if $::form->{new_parts_id};
+
+  $::auth->restore_form_from_session(delete $::form->{previousform});
+
+  # set item ids to new fake id, to identify them as new items
+  foreach my $item (@{$self->order->items_sorted}) {
+    $item->{new_fake_id} = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
+  }
+
+  $self->get_unalterable_data();
+  $self->pre_render();
+
+  # trigger rendering values for second row/longdescription as hidden,
+  # because they are loaded only on demand. So we need to keep the values
+  # from the source.
+  $_->{render_second_row}      = 1 for @{ $self->order->items_sorted };
+  $_->{render_longdescription} = 1 for @{ $self->order->items_sorted };
+
+  $self->render(
+    'delivery_order/form',
+    title => $self->get_title_for('edit'),
+    %{$self->{template_args}}
+  );
+
+}
+
+sub action_stock_in_out_dialog {
+  my ($self) = @_;
+
+  my $part    = SL::DB::Part->load_cached($::form->{parts_id}) or die "need parts_id";
+  my $unit    = SL::DB::Unit->load_cached($::form->{unit}) or die "need unit";
+  my $stock   = $::form->{stock};
+  my $row     = $::form->{row};
+  my $item_id = $::form->{item_id};
+  my $qty     = _parse_number($::form->{qty_as_number});
+
+  my $inout = $self->type_data->transfer;
+
+  my @contents   = DO->get_item_availability(parts_id => $part->id);
+  my $stock_info = DO->unpack_stock_information(packed => $stock);
+
+  $self->merge_stock_data($stock_info, \@contents, $part, $unit);
+
+  $self->render("delivery_order/stock_dialog", { layout => 0 },
+    WHCONTENTS => $self->order->delivered ? $stock_info : \@contents,
+    part       => $part,
+    do_qty     => $qty,
+    do_unit    => $unit->unit,
+    delivered  => $self->order->delivered,
+    row        => $row,
+    item_id    => $item_id,
+  );
+}
+
+sub action_update_stock_information {
+  my ($self) = @_;
+
+  my $stock_info = $::form->{stock_info};
+  my $unit = $::form->{unit};
+  my $yaml = SL::YAML::Dump($stock_info);
+  my $stock_qty = $self->calculate_stock_in_out_from_stock_info($unit, $stock_info);
+
+  my $response = {
+    stock_info => $yaml,
+    stock_qty => $stock_qty,
+  };
+  $self->render(\ SL::JSON::to_json($response), { layout => 0, type => 'json', process => 0 });
+}
+
+sub merge_stock_data {
+  my ($self, $stock_info, $contents, $part, $unit) = @_;
+  # TODO rewrite to mapping
+
+  if (!$self->order->delivered) {
+    for my $row (@$contents) {
+      # row here is in parts units. stock is in item units
+      $row->{available_qty} = _format_number($part->unit_obj->convert_to($row->{qty}, $unit));
+
+      for my $sinfo (@{ $stock_info }) {
+        next if $row->{bin_id}       != $sinfo->{bin_id} ||
+                $row->{warehouse_id} != $sinfo->{warehouse_id} ||
+                $row->{chargenumber} ne $sinfo->{chargenumber} ||
+                $row->{bestbefore}   ne $sinfo->{bestbefore};
+
+        $row->{"stock_$_"} = $sinfo->{$_}
+          for qw(qty unit error delivery_order_items_stock_id);
+      }
+    }
+
+  } else {
+    for my $sinfo (@{ $stock_info }) {
+      my $bin = SL::DB::Bin->load_cached($sinfo->{bin_id});
+      $sinfo->{warehousedescription} = $bin->warehouse->description;
+      $sinfo->{bindescription}       = $bin->description;
+      map { $sinfo->{"stock_$_"}      = $sinfo->{$_} } qw(qty unit);
+    }
+  }
+}
+
+# load the second row for one or more items
+#
+# This action gets the html code for all items second rows by rendering a template for
+# the second row and sets the html code via client js.
+sub action_load_second_rows {
+  my ($self) = @_;
+
+  foreach my $item_id (@{ $::form->{item_ids} }) {
+    my $idx  = first_index { $_ eq $item_id } @{ $::form->{orderitem_ids} };
+    my $item = $self->order->items_sorted->[$idx];
+
+    $self->js_load_second_row($item, $item_id, 0);
+  }
+
+  $self->js->run('kivi.DeliveryOrder.init_row_handlers') if $self->order->is_sales; # for lastcosts change-callback
+
+  $self->js->render();
+}
+
+# update description, notes and sellprice from master data
+sub action_update_row_from_master_data {
+  my ($self) = @_;
+
+  foreach my $item_id (@{ $::form->{item_ids} }) {
+    my $idx   = first_index { $_ eq $item_id } @{ $::form->{orderitem_ids} };
+    my $item  = $self->order->items_sorted->[$idx];
+    my $texts = get_part_texts($item->part, $self->order->language_id);
+
+    $item->description($texts->{description});
+    $item->longdescription($texts->{longdescription});
+
+    my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order);
+
+    my $price_src;
+    if ($item->part->is_assortment) {
+    # add assortment items with price 0, as the components carry the price
+      $price_src = $price_source->price_from_source("");
+      $price_src->price(0);
+    } else {
+      $price_src = $price_source->best_price
+                 ? $price_source->best_price
+                 : $price_source->price_from_source("");
+      $price_src->price($::form->round_amount($price_src->price / $self->order->exchangerate, 5)) if $self->order->exchangerate;
+      $price_src->price(0) if !$price_source->best_price;
+    }
+
+
+    $item->sellprice($price_src->price);
+    $item->active_price_source($price_src);
+
+    $self->js
+      ->run('kivi.DeliveryOrder.update_sellprice', $item_id, $item->sellprice_as_number)
+      ->html('.row_entry:has(#item_' . $item_id . ') [name = "partnumber"] a', $item->part->partnumber)
+      ->val ('.row_entry:has(#item_' . $item_id . ') [name = "order.orderitems[].description"]', $item->description)
+      ->val ('.row_entry:has(#item_' . $item_id . ') [name = "order.orderitems[].longdescription"]', $item->longdescription);
+
+    if ($self->search_cvpartnumber) {
+      $self->get_item_cvpartnumber($item);
+      $self->js->html('.row_entry:has(#item_' . $item_id . ') [name = "cvpartnumber"]', $item->{cvpartnumber});
+    }
+  }
+
+  $self->js_redisplay_line_values;
+
+  $self->js->render();
+}
+
+sub action_transfer_stock {
+  my ($self) = @_;
+
+  if ($self->order->delivered) {
+    return $self->js->flash("error", t8('The parts for this order have already been transferred'))->render;
+  }
+
+  my $inout = $self->type_data->properties('transfer');
+
+  my $errors = $self->save;
+
+  if (@$errors) {
+    $self->js->flash('error', $_) for @$errors;
+    return $self->js->render;
+  }
+
+  my $order = $self->order;
+
+  # TODO move to type data
+  my $trans_type = $inout eq 'in'
+    ? SL::DB::Manager::TransferType->find_by(direction => "id", description => "stock")
+    : SL::DB::Manager::TransferType->find_by(direction => "out", description => "shipped");
+
+  my @transfer_requests;
+
+  for my $item (@{ $order->items_sorted }) {
+    for my $stock (@{ $item->delivery_order_stock_entries }) {
+      my $transfer = SL::DB::Inventory->new_from($stock);
+      $transfer->trans_type($trans_type);
+      $transfer->qty($transfer->qty * -1) if $inout eq 'out';
+
+      push @transfer_requests, $transfer if defined $transfer->qty && $transfer->qty != 0;
+    };
+  }
+
+  if (!@transfer_requests) {
+    return $self->js->flash("error", t8("No stock to transfer"))->render;
+  }
+
+  SL::DB->client->with_transaction(sub {
+    $_->save for @transfer_requests;
+    $self->order->update_attributes(delivered => 1);
+  });
+
+  $self->js
+    ->flash("info", t8("Stock transfered"))
+    ->run('kivi.ActionBar.setDisabled', '#transfer_out_action', t8('The parts for this order have already been transferred'))
+    ->run('kivi.ActionBar.setDisabled', '#transfer_in_action', t8('The parts for this order have already been transferred'))
+    ->run('kivi.ActionBar.setDisabled', '#delete_action', t8('The parts for this order have already been transferred'))
+    ->replaceWith('#data-status-line', delivery_order_status_line($self->order))
+    ->render;
+
+}
+
+sub js_load_second_row {
+  my ($self, $item, $item_id, $do_parse) = @_;
+
+  if ($do_parse) {
+    # Parse values from form (they are formated while rendering (template)).
+    # Workaround to pre-parse number-cvars (parse_custom_variable_values does not parse number values).
+    # This parsing is not necessary at all, if we assure that the second row/cvars are only loaded once.
+    foreach my $var (@{ $item->cvars_by_config }) {
+      $var->unparsed_value($::form->parse_amount(\%::myconfig, $var->{__unparsed_value})) if ($var->config->type eq 'number' && exists($var->{__unparsed_value}));
+    }
+    $item->parse_custom_variable_values;
+  }
+
+  my $row_as_html = $self->p->render('delivery_order/tabs/_second_row', ITEM => $item, TYPE => $self->type);
+
+  $self->js
+    ->html('#second_row_' . $item_id, $row_as_html)
+    ->data('#second_row_' . $item_id, 'loaded', 1);
+}
+
+sub js_redisplay_line_values {
+  my ($self) = @_;
+
+  my $is_sales = $self->order->is_sales;
+
+  # sales orders with margins
+  my @data;
+  if ($is_sales) {
+    @data = map {
+      [
+       $::form->format_amount(\%::myconfig, $_->{linetotal},     2, 0),
+       $::form->format_amount(\%::myconfig, $_->{marge_total},   2, 0),
+       $::form->format_amount(\%::myconfig, $_->{marge_percent}, 2, 0),
+      ]} @{ $self->order->items_sorted };
+  } else {
+    @data = map {
+      [
+       $::form->format_amount(\%::myconfig, $_->{linetotal},     2, 0),
+      ]} @{ $self->order->items_sorted };
+  }
+
+  $self->js
+    ->run('kivi.DeliveryOrder.redisplay_line_values', $is_sales, \@data);
+}
+
+sub js_redisplay_cvpartnumbers {
+  my ($self) = @_;
+
+  $self->get_item_cvpartnumber($_) for @{$self->order->items_sorted};
+
+  my @data = map {[$_->{cvpartnumber}]} @{ $self->order->items_sorted };
+
+  $self->js
+    ->run('kivi.DeliveryOrder.redisplay_cvpartnumbers', \@data);
+}
+
+sub js_reset_order_and_item_ids_after_save {
+  my ($self) = @_;
+
+  $self->js
+    ->val('#id', $self->order->id)
+    ->val('#converted_from_oe_id', '')
+    ->val('#order_' . $self->nr_key(), $self->order->number);
+
+  my $idx = 0;
+  foreach my $form_item_id (@{ $::form->{orderitem_ids} }) {
+    next if !$self->order->items_sorted->[$idx]->id;
+    next if $form_item_id !~ m{^new};
+    $self->js
+      ->val ('[name="orderitem_ids[+]"][value="' . $form_item_id . '"]', $self->order->items_sorted->[$idx]->id)
+      ->val ('#item_' . $form_item_id, $self->order->items_sorted->[$idx]->id)
+      ->attr('#item_' . $form_item_id, "id", 'item_' . $self->order->items_sorted->[$idx]->id);
+  } continue {
+    $idx++;
+  }
+  $self->js->val('[name="converted_from_orderitems_ids[+]"]', '');
+}
+
+#
+# helpers
+#
+
+sub init_type {
+  my ($self) = @_;
+
+  if (none { $::form->{type} eq $_ } @{$self->valid_types}) {
+    die "Not a valid type for delivery order";
+  }
+
+  $self->type($::form->{type});
+}
+
+sub init_cv {
+  my ($self) = @_;
+
+  return $self->type_data->customervendor;
+}
+
+sub init_search_cvpartnumber {
+  my ($self) = @_;
+
+  my $user_prefs = SL::Helper::UserPreferences::PartPickerSearch->new();
+  my $search_cvpartnumber;
+  $search_cvpartnumber = !!$user_prefs->get_sales_search_customer_partnumber() if $self->cv eq 'customer';
+  $search_cvpartnumber = !!$user_prefs->get_purchase_search_makemodel()        if $self->cv eq 'vendor';
+
+  return $search_cvpartnumber;
+}
+
+sub init_show_update_button {
+  my ($self) = @_;
+
+  !!SL::Helper::UserPreferences::UpdatePositions->new()->get_show_update_button();
+}
+
+sub init_p {
+  SL::Presenter->get;
+}
+
+sub init_order {
+  $_[0]->make_order;
+}
+
+sub init_all_price_factors {
+  SL::DB::Manager::PriceFactor->get_all;
+}
+
+sub init_part_picker_classification_ids {
+  my ($self)    = @_;
+
+  return [ map { $_->id } @{ SL::DB::Manager::PartClassification->get_all(where => $self->type_data->part_classification_query) } ];
+}
+
+sub check_auth {
+  my ($self) = @_;
+
+  $::auth->assert($self->type_data->access('view') || 'DOES_NOT_EXIST');
+}
+
+sub check_auth_for_edit {
+  my ($self) = @_;
+
+  $::auth->assert($self->type_data->access('edit') || 'DOES_NOT_EXIST');
+}
+
+# build the selection box for contacts
+#
+# Needed, if customer/vendor changed.
+sub build_contact_select {
+  my ($self) = @_;
+
+  select_tag('order.cp_id', [ $self->order->{$self->cv}->contacts ],
+    value_key  => 'cp_id',
+    title_key  => 'full_name_dep',
+    default    => $self->order->cp_id,
+    with_empty => 1,
+    style      => 'width: 300px',
+  );
+}
+
+# build the selection box for shiptos
+#
+# Needed, if customer/vendor changed.
+sub build_shipto_select {
+  my ($self) = @_;
+
+  select_tag('order.shipto_id',
+             [ {displayable_id => t8("No/individual shipping address"), shipto_id => ''}, $self->order->{$self->cv}->shipto ],
+             value_key  => 'shipto_id',
+             title_key  => 'displayable_id',
+             default    => $self->order->shipto_id,
+             with_empty => 0,
+             style      => 'width: 300px',
+  );
+}
+
+# build the inputs for the cusom shipto dialog
+#
+# Needed, if customer/vendor changed.
+sub build_shipto_inputs {
+  my ($self) = @_;
+
+  my $content = $self->p->render('common/_ship_to_dialog',
+                                 vc_obj      => $self->order->customervendor,
+                                 cs_obj      => $self->order->custom_shipto,
+                                 cvars       => $self->order->custom_shipto->cvars_by_config,
+                                 id_selector => '#order_shipto_id');
+
+  div_tag($content, id => 'shipto_inputs');
+}
+
+# render the info line for business
+#
+# Needed, if customer/vendor changed.
+sub build_business_info_row
+{
+  $_[0]->p->render('delivery_order/tabs/_business_info_row', SELF => $_[0]);
+}
+
+
+sub load_order {
+  my ($self) = @_;
+
+  return if !$::form->{id};
+
+  $self->order(SL::DB::DeliveryOrder->new(id => $::form->{id})->load);
+
+  # Add an empty custom shipto to the order, so that the dialog can render the cvar inputs.
+  # You need a custom shipto object to call cvars_by_config to get the cvars.
+  $self->order->custom_shipto(SL::DB::Shipto->new(module => 'OE', custom_variables => [])) if !$self->order->custom_shipto;
+
+  $self->prepare_stock_info($_) for $self->order->items;
+
+  return $self->order;
+}
+
+# load or create a new order object
+#
+# And assign changes from the form to this object.
+# If the order is loaded from db, check if items are deleted in the form,
+# remove them form the object and collect them for removing from db on saving.
+# Then create/update items from form (via make_item) and add them.
+sub make_order {
+  my ($self) = @_;
+
+  # add_items adds items to an order with no items for saving, but they cannot
+  # be retrieved via items until the order is saved. Adding empty items to new
+  # order here solves this problem.
+  my $order;
+  $order   = SL::DB::DeliveryOrder->new(id => $::form->{id})->load(with => [ 'orderitems', 'orderitems.part' ]) if $::form->{id};
+  $order ||= SL::DB::DeliveryOrder->new(orderitems  => [], currency_id => $::instance_conf->get_currency_id(), order_type => $self->type_data->validate($::form->{type}));
+
+  my $cv_id_method = $self->cv . '_id';
+  if (!$::form->{id} && $::form->{$cv_id_method}) {
+    $order->$cv_id_method($::form->{$cv_id_method});
+    setup_order_from_cv($order);
+  }
+
+  my $form_orderitems                  = delete $::form->{order}->{orderitems};
+
+  $order->assign_attributes(%{$::form->{order}});
+
+  $self->setup_custom_shipto_from_form($order, $::form);
+
+  # remove deleted items
+  $self->item_ids_to_delete([]);
+  foreach my $idx (reverse 0..$#{$order->orderitems}) {
+    my $item = $order->orderitems->[$idx];
+    if (none { $item->id == $_->{id} } @{$form_orderitems}) {
+      splice @{$order->orderitems}, $idx, 1;
+      push @{$self->item_ids_to_delete}, $item->id;
+    }
+  }
+
+  my @items;
+  my $pos = 1;
+  foreach my $form_attr (@{$form_orderitems}) {
+    my $item = make_item($order, $form_attr);
+    $item->position($pos);
+    push @items, $item;
+    $pos++;
+  }
+
+  $self->prepare_stock_info($_) for $order->items, @items;
+
+  $order->add_items(grep {!$_->id} @items);
+
+  return $order;
+}
+
+# create or update items from form
+#
+# Make item objects from form values. For items already existing read from db.
+# Create a new item else. And assign attributes.
+sub make_item {
+  my ($record, $attr) = @_;
+
+  my $item;
+  $item = first { $_->id == $attr->{id} } @{$record->items} if $attr->{id};
+
+  my $is_new = !$item;
+
+  # add_custom_variables adds cvars to an orderitem with no cvars for saving, but
+  # they cannot be retrieved via custom_variables until the order/orderitem is
+  # saved. Adding empty custom_variables to new orderitem here solves this problem.
+  $item ||= SL::DB::DeliveryOrderItem->new(custom_variables => []);
+
+  # handle stock info
+  if (my $stock_info = delete $attr->{stock_info}) {
+    my %existing = map { $_->id => $_ } $item->delivery_order_stock_entries;
+    my @save;
+
+    for my $line (@{ DO->unpack_stock_information(packed => $stock_info) }) {
+      # lookup existing or make new
+      my $obj = delete $existing{$line->{delivery_order_items_stock_id}}
+             // SL::DB::DeliveryOrderItemsStock->new;
+
+      # assign attributes
+      $obj->$_($line->{$_}) for qw(bin_id warehouse_id chargenumber qty unit);
+      $obj->bestbefore_as_date($line->{bestfbefore})
+        if $line->{bestbefore} && $::instance_conf->get_show_bestbefore;
+      push @save, $obj if $obj->qty;
+    }
+
+    $item->delivery_order_stock_entries(@save);
+  }
+
+  $item->assign_attributes(%$attr);
+
+  if ($is_new) {
+    my $texts = get_part_texts($item->part, $record->language_id);
+    $item->longdescription($texts->{longdescription})              if !defined $attr->{longdescription};
+    $item->project_id($record->globalproject_id)                   if !defined $attr->{project_id};
+    $item->lastcost($record->is_sales ? $item->part->lastcost : 0) if !defined $attr->{lastcost_as_number};
+  }
+
+  return $item;
+}
+
+# create a new item
+#
+# This is used to add one item
+sub new_item {
+  my ($record, $attr) = @_;
+
+  my $item = SL::DB::DeliveryOrderItem->new;
+
+  # Remove attributes where the user left or set the inputs empty.
+  # So these attributes will be undefined and we can distinguish them
+  # from zero later on.
+  for (qw(qty_as_number sellprice_as_number discount_as_percent)) {
+    delete $attr->{$_} if $attr->{$_} eq '';
+  }
+
+  $item->assign_attributes(%$attr);
+
+  my $part         = SL::DB::Part->new(id => $attr->{parts_id})->load;
+  my $price_source = SL::PriceSource->new(record_item => $item, record => $record);
+
+  $item->unit($part->unit) if !$item->unit;
+
+  my $price_src;
+  if ( $part->is_assortment ) {
+    # add assortment items with price 0, as the components carry the price
+    $price_src = $price_source->price_from_source("");
+    $price_src->price(0);
+  } elsif (defined $item->sellprice) {
+    $price_src = $price_source->price_from_source("");
+    $price_src->price($item->sellprice);
+  } else {
+    $price_src = $price_source->best_price
+               ? $price_source->best_price
+               : $price_source->price_from_source("");
+    $price_src->price(0) if !$price_source->best_price;
+  }
+
+  my $discount_src;
+  if (defined $item->discount) {
+    $discount_src = $price_source->discount_from_source("");
+    $discount_src->discount($item->discount);
+  } else {
+    $discount_src = $price_source->best_discount
+                  ? $price_source->best_discount
+                  : $price_source->discount_from_source("");
+    $discount_src->discount(0) if !$price_source->best_discount;
+  }
+
+  my %new_attr;
+  $new_attr{part}                   = $part;
+  $new_attr{description}            = $part->description     if ! $item->description;
+  $new_attr{qty}                    = 1.0                    if ! $item->qty;
+  $new_attr{price_factor_id}        = $part->price_factor_id if ! $item->price_factor_id;
+  $new_attr{sellprice}              = $price_src->price;
+  $new_attr{discount}               = $discount_src->discount;
+  $new_attr{active_price_source}    = $price_src;
+  $new_attr{active_discount_source} = $discount_src;
+  $new_attr{longdescription}        = $part->notes           if ! defined $attr->{longdescription};
+  $new_attr{project_id}             = $record->globalproject_id;
+  $new_attr{lastcost}               = $record->is_sales ? $part->lastcost : 0;
+
+  # add_custom_variables adds cvars to an orderitem with no cvars for saving, but
+  # they cannot be retrieved via custom_variables until the order/orderitem is
+  # saved. Adding empty custom_variables to new orderitem here solves this problem.
+  $new_attr{custom_variables} = [];
+
+  my $texts = get_part_texts($part, $record->language_id, description => $new_attr{description}, longdescription => $new_attr{longdescription});
+
+  $item->assign_attributes(%new_attr, %{ $texts });
+
+  return $item;
+}
+
+sub prepare_stock_info {
+  my ($self, $item) = @_;
+
+  $item->{stock_info} = SL::YAML::Dump([
+    map +{
+      delivery_order_items_stock_id => $_->id,
+      qty                           => $_->qty,
+      warehouse_id                  => $_->warehouse_id,
+      bin_id                        => $_->bin_id,
+      chargenumber                  => $_->chargenumber,
+      unit                          => $_->unit,
+    }, $item->delivery_order_stock_entries
+  ]);
+}
+
+sub setup_order_from_cv {
+  my ($order) = @_;
+
+  $order->$_($order->customervendor->$_) for (qw(taxzone_id payment_id delivery_term_id currency_id));
+
+  $order->intnotes($order->customervendor->notes);
+
+  if ($order->is_sales) {
+    $order->salesman_id($order->customer->salesman_id || SL::DB::Manager::Employee->current->id);
+    $order->taxincluded(defined($order->customer->taxincluded_checked)
+                        ? $order->customer->taxincluded_checked
+                        : $::myconfig{taxincluded_checked});
+  }
+
+}
+
+# setup custom shipto from form
+#
+# The dialog returns form variables starting with 'shipto' and cvars starting
+# with 'shiptocvar_'.
+# Mark it to be deleted if a shipto from master data is selected
+# (i.e. order has a shipto).
+# Else, update or create a new custom shipto. If the fields are empty, it
+# will not be saved on save.
+sub setup_custom_shipto_from_form {
+  my ($self, $order, $form) = @_;
+
+  if ($order->shipto) {
+    $self->is_custom_shipto_to_delete(1);
+  } else {
+    my $custom_shipto = $order->custom_shipto || $order->custom_shipto(SL::DB::Shipto->new(module => 'OE', custom_variables => []));
+
+    my $shipto_cvars  = {map { my ($key) = m{^shiptocvar_(.+)}; $key => delete $form->{$_}} grep { m{^shiptocvar_} } keys %$form};
+    my $shipto_attrs  = {map {                                  $_   => delete $form->{$_}} grep { m{^shipto}      } keys %$form};
+
+    $custom_shipto->assign_attributes(%$shipto_attrs);
+    $custom_shipto->cvar_by_name($_)->value($shipto_cvars->{$_}) for keys %$shipto_cvars;
+  }
+}
+
+# get data for saving, printing, ..., that is not changed in the form
+#
+# Only cvars for now.
+sub get_unalterable_data {
+  my ($self) = @_;
+
+  foreach my $item (@{ $self->order->items }) {
+    # autovivify all cvars that are not in the form (cvars_by_config can do it).
+    # workaround to pre-parse number-cvars (parse_custom_variable_values does not parse number values).
+    foreach my $var (@{ $item->cvars_by_config }) {
+      $var->unparsed_value($::form->parse_amount(\%::myconfig, $var->{__unparsed_value})) if ($var->config->type eq 'number' && exists($var->{__unparsed_value}));
+    }
+    $item->parse_custom_variable_values;
+  }
+}
+
+# delete the order
+#
+# And remove related files in the spool directory
+sub delete {
+  my ($self) = @_;
+
+  my $errors = [];
+  my $db     = $self->order->db;
+
+  $db->with_transaction(
+    sub {
+      my @spoolfiles = grep { $_ } map { $_->spoolfile } @{ SL::DB::Manager::Status->get_all(where => [ trans_id => $self->order->id ]) };
+      $self->order->delete;
+      my $spool = $::lx_office_conf{paths}->{spool};
+      unlink map { "$spool/$_" } @spoolfiles if $spool;
+
+      $self->save_history('DELETED');
+
+      1;
+  }) || push(@{$errors}, $db->error);
+
+  return $errors;
+}
+
+# save the order
+#
+# And delete items that are deleted in the form.
+sub save {
+  my ($self) = @_;
+
+  my $errors = [];
+  my $db     = $self->order->db;
+
+  $db->with_transaction(sub {
+    # delete custom shipto if it is to be deleted or if it is empty
+    if ($self->order->custom_shipto && ($self->is_custom_shipto_to_delete || $self->order->custom_shipto->is_empty)) {
+      $self->order->custom_shipto->delete if $self->order->custom_shipto->shipto_id;
+      $self->order->custom_shipto(undef);
+    }
+
+    SL::DB::DeliveryOrderItem->new(id => $_)->delete for @{$self->item_ids_to_delete || []};
+    $self->order->save(cascade => 1);
+
+    # link records
+    if ($::form->{converted_from_oe_id}) {
+      my @converted_from_oe_ids = split ' ', $::form->{converted_from_oe_id};
+      foreach my $converted_from_oe_id (@converted_from_oe_ids) {
+        my $src = SL::DB::Order->new(id => $converted_from_oe_id)->load;
+        $src->update_attributes(closed => 1) if $src->type =~ /_quotation$/ && $self->order->is_type(PURCHASE_DELIVERY_ORDER_TYPE);
+        $src->link_to_record($self->order);
+      }
+      if (scalar @{ $::form->{converted_from_orderitems_ids} || [] }) {
+        my $idx = 0;
+        foreach (@{ $self->order->items_sorted }) {
+          my $from_id = $::form->{converted_from_orderitems_ids}->[$idx];
+          next if !$from_id;
+          SL::DB::RecordLink->new(from_table => 'orderitems',
+                                  from_id    => $from_id,
+                                  to_table   => 'orderitems',
+                                  to_id      => $_->id
+          )->save;
+          $idx++;
+        }
+      }
+    }
+
+    $self->save_history('SAVED');
+
+    1;
+  }) || push(@{$errors}, $db->error);
+
+  return $errors;
+}
+
+sub workflow_sales_or_request_for_quotation {
+  my ($self) = @_;
+
+  # always save
+  my $errors = $self->save();
+
+  if (scalar @{ $errors }) {
+    $self->js->flash('error', $_) for @{ $errors };
+    return $self->js->render();
+  }
+
+  my $destination_type = $self->type_data->workflow("to_quotation_type");
+
+  $self->order(SL::DB::DeliveryOrder->new_from($self->order, destination_type => $destination_type));
+  $self->{converted_from_oe_id} = delete $::form->{id};
+
+  # set item ids to new fake id, to identify them as new items
+  foreach my $item (@{$self->order->items_sorted}) {
+    $item->{new_fake_id} = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
+  }
+
+  # change form type
+  $::form->{type} = $destination_type;
+  $self->type($self->init_type);
+  $self->cv  ($self->init_cv);
+  $self->check_auth;
+
+  $self->get_unalterable_data();
+  $self->pre_render();
+
+  # trigger rendering values for second row as hidden, because they
+  # are loaded only on demand. So we need to keep the values from the
+  # source.
+  $_->{render_second_row} = 1 for @{ $self->order->items_sorted };
+
+  $self->render(
+    'delivery_order/form',
+    title => $self->get_title_for('edit'),
+    %{$self->{template_args}}
+  );
+}
+
+sub workflow_sales_or_purchase_order {
+  my ($self) = @_;
+
+  # always save
+  my $errors = $self->save();
+
+  if (scalar @{ $errors }) {
+    $self->js->flash('error', $_) foreach @{ $errors };
+    return $self->js->render();
+  }
+
+  my $destination_type = $self->type_data->workflow("to_order_type");
+
+  # check for direct delivery
+  # copy shipto in custom shipto (custom shipto will be copied by new_from() in case)
+  my $custom_shipto;
+  if ($self->type_data->workflow("to_order_copy_shipto") && $::form->{use_shipto} && $self->order->shipto) {
+    $custom_shipto = $self->order->shipto->clone('SL::DB::DeliveryOrder');
+  }
+
+  $self->order(SL::DB::DeliveryOrder->new_from($self->order, destination_type => $destination_type));
+  $self->{converted_from_oe_id} = delete $::form->{id};
+
+  # set item ids to new fake id, to identify them as new items
+  foreach my $item (@{$self->order->items_sorted}) {
+    $item->{new_fake_id} = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
+  }
+
+  if ($self->type_data->workflow("to_order_copy_shipto")) {
+    if ($::form->{use_shipto}) {
+      $self->order->custom_shipto($custom_shipto) if $custom_shipto;
+    } else {
+      # remove any custom shipto if not wanted
+      $self->order->custom_shipto(SL::DB::Shipto->new(module => 'OE', custom_variables => []));
+    }
+  }
+
+  # change form type
+  $::form->{type} = $destination_type;
+  $self->type($self->init_type);
+  $self->cv  ($self->init_cv);
+  $self->check_auth;
+
+  $self->get_unalterable_data();
+  $self->pre_render();
+
+  # trigger rendering values for second row as hidden, because they
+  # are loaded only on demand. So we need to keep the values from the
+  # source.
+  $_->{render_second_row} = 1 for @{ $self->order->items_sorted };
+
+  $self->render(
+    'delivery_order/form',
+    title => $self->get_title_for('edit'),
+    %{$self->{template_args}}
+  );
+}
+
+sub pre_render {
+  my ($self) = @_;
+
+  $self->{all_taxzones}               = SL::DB::Manager::TaxZone->get_all_sorted();
+  $self->{all_currencies}             = SL::DB::Manager::Currency->get_all_sorted();
+  $self->{all_departments}            = SL::DB::Manager::Department->get_all_sorted();
+  $self->{all_languages}              = SL::DB::Manager::Language->get_all_sorted( query => [ or => [ obsolete => 0, id => $self->order->language_id ] ] );
+  $self->{all_employees}              = SL::DB::Manager::Employee->get_all(where => [ or => [ id => $self->order->employee_id,
+                                                                                              deleted => 0 ] ],
+                                                                           sort_by => 'name');
+  $self->{all_salesmen}               = SL::DB::Manager::Employee->get_all(where => [ or => [ id => $self->order->salesman_id,
+                                                                                              deleted => 0 ] ],
+                                                                           sort_by => 'name');
+  $self->{all_payment_terms}          = SL::DB::Manager::PaymentTerm->get_all_sorted(where => [ or => [ id => $self->order->payment_id,
+                                                                                                        obsolete => 0 ] ]);
+  $self->{all_delivery_terms}         = SL::DB::Manager::DeliveryTerm->get_all_sorted();
+  $self->{current_employee_id}        = SL::DB::Manager::Employee->current->id;
+  $self->{order_probabilities}        = [ map { { title => ($_ * 10) . '%', id => $_ * 10 } } (0..10) ];
+  $self->{positions_scrollbar_height} = SL::Helper::UserPreferences::PositionsScrollbar->new()->get_height();
+
+  my $print_form = Form->new('');
+  $print_form->{type}        = $self->type;
+  $print_form->{printers}    = SL::DB::Manager::Printer->get_all_sorted;
+  $self->{print_options}     = SL::Helper::PrintOptions->get_print_options(
+    form => $print_form,
+    options => {dialog_name_prefix => 'print_options.',
+                show_headers       => 1,
+                no_queue           => 1,
+                no_postscript      => 1,
+                no_opendocument    => 0,
+                no_html            => 1},
+  );
+
+  foreach my $item (@{$self->order->orderitems}) {
+    my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order);
+    $item->active_price_source(   $price_source->price_from_source(   $item->active_price_source   ));
+    $item->active_discount_source($price_source->discount_from_source($item->active_discount_source));
+  }
+
+  if ($self->order->${\ $self->type_data->nr_key } && $::instance_conf->get_webdav) {
+    my $webdav = SL::Webdav->new(
+      type     => $self->type,
+      number   => $self->order->number,
+    );
+    my @all_objects = $webdav->get_all_objects;
+    @{ $self->{template_args}->{WEBDAV} } = map { { name => $_->filename,
+                                                    type => t8('File'),
+                                                    link => File::Spec->catfile($_->full_filedescriptor),
+                                                } } @all_objects;
+  }
+
+  $self->{template_args}{in_out}                                 = $self->type_data->transfer;
+  $self->{template_args}{longdescription_dialog_size_percentage} = SL::Helper::UserPreferences::DisplayPreferences->new()->get_longdescription_dialog_size_percentage();
+
+  $self->get_item_cvpartnumber($_) for @{$self->order->items_sorted};
+
+  $::request->{layout}->use_javascript("${_}.js") for qw(kivi.SalesPurchase kivi.DeliveryOrder kivi.File ckeditor/ckeditor ckeditor/adapters/jquery
+                                                         calculate_qty kivi.Validator follow_up show_history);
+  $self->setup_edit_action_bar;
+}
+
+sub setup_edit_action_bar {
+  my ($self, %params) = @_;
+
+  my $deletion_allowed = $self->type_data->show_menu("delete");
+  my $may_edit_create  = $::auth->assert($self->type_data->access('edit') || 'DOES_NOT_EXIST', 1);
+
+  for my $bar ($::request->layout->get('actionbar')) {
+    $bar->add(
+      combobox => [
+        action => [
+          t8('Save'),
+          call     => [ 'kivi.DeliveryOrder.save', 'save', $::instance_conf->get_order_warn_duplicate_parts,
+                                                           $::instance_conf->get_order_warn_no_deliverydate,
+          ],
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save as new'),
+          call     => [ 'kivi.DeliveryOrder.save', 'save_as_new', $::instance_conf->get_order_warn_duplicate_parts ],
+          disabled => !$may_edit_create                        ? t8('You do not have the permissions to access this function.')
+                    : $self->type eq 'supplier_delivery_order' ? t8('Need a workflow for Supplier Delivery Order')
+                    : !$self->order->id                        ? t8('This object has not been saved yet.')
+                    :                                            undef,
+        ],
+      ], # end of combobox "Save"
+
+      combobox => [
+        action => [
+          t8('Workflow'),
+        ],
+        action => [
+          t8('Save and Quotation'),
+          submit   => [ '#order_form', { action => "DeliveryOrder/sales_quotation" } ],
+          only_if  => $self->type_data->show_menu("save_and_quotation"),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and RFQ'),
+          submit   => [ '#order_form', { action => "DeliveryOrder/request_for_quotation" } ],
+          only_if  => $self->type_data->show_menu("save_and_rfq"),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and Sales Order'),
+          submit   => [ '#order_form', { action => "DeliveryOrder/sales_order" } ],
+          only_if  => $self->type_data->show_menu("save_and_sales_order"),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and Purchase Order'),
+          call     => [ 'kivi.DeliveryOrder.purchase_order_check_for_direct_delivery' ],
+          only_if  => $self->type_data->show_menu("save_and_purchase_order"),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and Delivery Order'),
+          call     => [ 'kivi.DeliveryOrder.save', 'save_and_delivery_order', $::instance_conf->get_order_warn_duplicate_parts,
+                                                                              $::instance_conf->get_order_warn_no_deliverydate,
+          ],
+          only_if  => $self->type_data->show_menu("save_and_delivery_order"),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and Invoice'),
+          call     => [ 'kivi.DeliveryOrder.save', 'save_and_invoice', $::instance_conf->get_order_warn_duplicate_parts ],
+          only_if  => $self->type_data->show_menu("save_and_invoice"),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and AP Transaction'),
+          call     => [ 'kivi.DeliveryOrder.save', 'save_and_ap_transaction', $::instance_conf->get_order_warn_duplicate_parts ],
+          only_if  => $self->type_data->show_menu("save_and_ap_transaction"),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+
+      ], # end of combobox "Workflow"
+
+      combobox => [
+        action => [
+          t8('Export'),
+        ],
+        action => [
+          t8('Save and preview PDF'),
+           call    => [ 'kivi.DeliveryOrder.save', 'preview_pdf', $::instance_conf->get_order_warn_duplicate_parts,
+                                                                  $::instance_conf->get_order_warn_no_deliverydate,
+          ],
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and print'),
+          call     => [ 'kivi.DeliveryOrder.show_print_options', $::instance_conf->get_order_warn_duplicate_parts,
+                                                                 $::instance_conf->get_order_warn_no_deliverydate,
+          ],
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and E-mail'),
+          id       => 'save_and_email_action',
+          call     => [ 'kivi.DeliveryOrder.save', 'save_and_show_email_dialog', $::instance_conf->get_order_warn_duplicate_parts,
+                                                                                 $::instance_conf->get_order_warn_no_deliverydate,
+          ],
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.')
+                    : !$self->order->id ? t8('This object has not been saved yet.')
+                    :                     undef,
+        ],
+        action => [
+          t8('Download attachments of all parts'),
+          call     => [ 'kivi.File.downloadOrderitemsFiles', $::form->{type}, $::form->{id} ],
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.')
+                    : !$self->order->id ? t8('This object has not been saved yet.')
+                    :                     undef,
+          only_if  => $::instance_conf->get_doc_storage,
+        ],
+      ], # end of combobox "Export"
+
+      action => [
+        t8('Delete'),
+        id       => 'delete_action',
+        call     => [ 'kivi.DeliveryOrder.delete_order' ],
+        confirm  => $::locale->text('Do you really want to delete this object?'),
+        disabled => !$may_edit_create       ? t8('You do not have the permissions to access this function.')
+                  : !$self->order->id       ? t8('This object has not been saved yet.')
+                  : $self->order->delivered ? t8('The parts for this order have already been transferred')
+                  :                           undef,
+        only_if  => $self->type_data->show_menu("delete"),
+      ],
+
+      combobox => [
+        action => [
+          t8('Transfer out'),
+          id       => 'transfer_out_action',
+          call     => [ 'kivi.DeliveryOrder.save', 'transfer_stock' ],
+          disabled => !$may_edit_create       ? t8('You do not have the permissions to access this function.')
+                    : !$self->order->id       ? t8('This object has not been saved yet.')
+                    : $self->order->delivered ? t8('The parts for this order have already been transferred')
+                    :                           undef,
+          only_if  => $self->type_data->properties('transfer') eq 'out',
+          confirm  => t8('Do you really want to transfer the stock and set this order to delivered?'),
+        ],
+        action => [
+          t8('Transfer in'),
+          id       => 'transfer_in_action',
+          call     => [ 'kivi.DeliveryOrder.save', 'transfer_stock' ],
+          disabled => !$may_edit_create       ? t8('You do not have the permissions to access this function.')
+                    : !$self->order->id       ? t8('This object has not been saved yet.')
+                    : $self->order->delivered ? t8('The parts for this order have already been transferred')
+                    :                           undef,
+          only_if  => $self->type_data->properties('transfer') eq 'in',
+          confirm  => t8('Do you really want to transfer the stock and set this order to delivered?'),
+        ],
+      ],
+
+      combobox => [
+        action => [
+          t8('more')
+        ],
+        action => [
+          t8('Follow-Up'),
+          call     => [ 'kivi.DeliveryOrder.follow_up_window' ],
+          disabled => !$self->order->id ? t8('This object has not been saved yet.') : undef,
+          only_if  => $::auth->assert('productivity', 1),
+        ],
+        action => [
+          t8('History'),
+          call     => [ 'set_history_window', $self->order->id, 'id' ],
+          disabled => !$self->order->id ? t8('This record has not been saved yet.') : undef,
+        ],
+      ], # end of combobox "more"
+    );
+  }
+}
+
+sub generate_pdf {
+  my ($order, $pdf_ref, $params) = @_;
+
+  my @errors = ();
+
+  my $print_form = Form->new('');
+  $print_form->{type}        = $order->type;
+  $print_form->{formname}    = $params->{formname} || $order->type;
+  $print_form->{format}      = $params->{format}   || 'pdf';
+  $print_form->{media}       = $params->{media}    || 'file';
+  $print_form->{groupitems}  = $params->{groupitems};
+  $print_form->{printer_id}  = $params->{printer_id};
+  $print_form->{media}       = 'file'                             if $print_form->{media} eq 'screen';
+
+  $order->language($params->{language});
+  $order->flatten_to_form($print_form, format_amounts => 1);
+
+  my $template_ext;
+  my $template_type;
+  if ($print_form->{format} =~ /(opendocument|oasis)/i) {
+    $template_ext  = 'odt';
+    $template_type = 'OpenDocument';
+  }
+
+  # search for the template
+  my ($template_file, @template_files) = SL::Helper::CreatePDF->find_template(
+    name        => $print_form->{formname},
+    extension   => $template_ext,
+    email       => $print_form->{media} eq 'email',
+    language    => $params->{language},
+    printer_id  => $print_form->{printer_id},
+  );
+
+  if (!defined $template_file) {
+    push @errors, $::locale->text('Cannot find matching template for this print request. Please contact your template maintainer. I tried these: #1.', join ', ', map { "'$_'"} @template_files);
+  }
+
+  return @errors if scalar @errors;
+
+  $print_form->throw_on_error(sub {
+    eval {
+      $print_form->prepare_for_printing;
+
+      $$pdf_ref = SL::Helper::CreatePDF->create_pdf(
+        format        => $print_form->{format},
+        template_type => $template_type,
+        template      => $template_file,
+        variables     => $print_form,
+        variable_content_types => {
+          longdescription => 'html',
+          partnotes       => 'html',
+          notes           => 'html',
+        },
+      );
+      1;
+    } || push @errors, ref($EVAL_ERROR) eq 'SL::X::FormError' ? $EVAL_ERROR->error : $EVAL_ERROR;
+  });
+
+  return @errors;
+}
+
+sub get_files_for_email_dialog {
+  my ($self) = @_;
+
+  my %files = map { ($_ => []) } qw(versions files vc_files part_files);
+
+  return %files if !$::instance_conf->get_doc_storage;
+
+  if ($self->order->id) {
+    $files{versions} = [ SL::File->get_all_versions(object_id => $self->order->id,              object_type => $self->order->type, file_type => 'document') ];
+    $files{files}    = [ SL::File->get_all(         object_id => $self->order->id,              object_type => $self->order->type, file_type => 'attachment') ];
+    $files{vc_files} = [ SL::File->get_all(         object_id => $self->order->{$self->cv}->id, object_type => $self->cv,          file_type => 'attachment') ];
+    $files{project_files} = [ SL::File->get_all(    object_id => $self->order->globalproject_id, object_type => 'project',         file_type => 'attachment') ];
+  }
+
+  my @parts =
+    uniq_by { $_->{id} }
+    map {
+      +{ id         => $_->part->id,
+         partnumber => $_->part->partnumber }
+    } @{$self->order->items_sorted};
+
+  foreach my $part (@parts) {
+    my @pfiles = SL::File->get_all(object_id => $part->{id}, object_type => 'part');
+    push @{ $files{part_files} }, map { +{ %{ $_ }, partnumber => $part->{partnumber} } } @pfiles;
+  }
+
+  foreach my $key (keys %files) {
+    $files{$key} = [ sort_by { lc $_->{db_file}->{file_name} } @{ $files{$key} } ];
+  }
+
+  return %files;
+}
+
+sub get_title_for {
+  my ($self, $action) = @_;
+
+  return '' if none { lc($action)} qw(add edit);
+  return $self->type_data->text($action);
+}
+
+sub get_item_cvpartnumber {
+  my ($self, $item) = @_;
+
+  return if !$self->search_cvpartnumber;
+  return if !$self->order->customervendor;
+
+  if ($self->cv eq 'vendor') {
+    my @mms = grep { $_->make eq $self->order->customervendor->id } @{$item->part->makemodels};
+    $item->{cvpartnumber} = $mms[0]->model if scalar @mms;
+  } elsif ($self->cv eq 'customer') {
+    my @cps = grep { $_->customer_id eq $self->order->customervendor->id } @{$item->part->customerprices};
+    $item->{cvpartnumber} = $cps[0]->customer_partnumber if scalar @cps;
+  }
+}
+
+sub get_part_texts {
+  my ($part_or_id, $language_or_id, %defaults) = @_;
+
+  my $part        = ref($part_or_id)     ? $part_or_id         : SL::DB::Part->load_cached($part_or_id);
+  my $language_id = ref($language_or_id) ? $language_or_id->id : $language_or_id;
+  my $texts       = {
+    description     => $defaults{description}     // $part->description,
+    longdescription => $defaults{longdescription} // $part->notes,
+  };
+
+  return $texts unless $language_id;
+
+  my $translation = SL::DB::Manager::Translation->get_first(
+    where => [
+      parts_id    => $part->id,
+      language_id => $language_id,
+    ]);
+
+  $texts->{description}     = $translation->translation     if $translation && $translation->translation;
+  $texts->{longdescription} = $translation->longdescription if $translation && $translation->longdescription;
+
+  return $texts;
+}
+
+sub nr_key {
+  return $_[0]->type_data->nr_key;
+}
+
+sub save_and_redirect_to {
+  my ($self, %params) = @_;
+
+  my $errors = $self->save();
+
+  if (scalar @{ $errors }) {
+    $self->js->flash('error', $_) foreach @{ $errors };
+    return $self->js->render();
+  }
+
+  flash_later('info', $self->type_data->text("saved"));
+
+  $self->redirect_to(%params, id => $self->order->id);
+}
+
+sub save_history {
+  my ($self, $addition) = @_;
+
+  my $number_type = $self->nr_key;
+  my $snumbers    = $number_type . '_' . $self->order->$number_type;
+
+  SL::DB::History->new(
+    trans_id    => $self->order->id,
+    employee_id => SL::DB::Manager::Employee->current->id,
+    what_done   => $self->order->type,
+    snumbers    => $snumbers,
+    addition    => $addition,
+  )->save;
+}
+
+sub store_pdf_to_webdav_and_filemanagement {
+  my($order, $content, $filename) = @_;
+
+  my @errors;
+
+  # copy file to webdav folder
+  if ($order->number && $::instance_conf->get_webdav_documents) {
+    my $webdav = SL::Webdav->new(
+      type     => $order->type,
+      number   => $order->number,
+    );
+    my $webdav_file = SL::Webdav::File->new(
+      webdav   => $webdav,
+      filename => $filename,
+    );
+    eval {
+      $webdav_file->store(data => \$content);
+      1;
+    } or do {
+      push @errors, t8('Storing PDF to webdav folder failed: #1', $@);
+    };
+  }
+  if ($order->id && $::instance_conf->get_doc_storage) {
+    eval {
+      SL::File->save(object_id     => $order->id,
+                     object_type   => $order->type,
+                     mime_type     => 'application/pdf',
+                     source        => 'created',
+                     file_type     => 'document',
+                     file_name     => $filename,
+                     file_contents => $content);
+      1;
+    } or do {
+      push @errors, t8('Storing PDF in storage backend failed: #1', $@);
+    };
+  }
+
+  return @errors;
+}
+
+sub calculate_stock_in_out_from_stock_info {
+  my ($self, $unit, $stock_info) = @_;
+
+  return "" if !$unit;
+
+  my %units_by_name = map { $_->name => $_ } @{ SL::DB::Manager::Unit->get_all };
+
+  my $sum      = sum0 map {
+    $units_by_name{$_->{unit}}->convert_to($_->{qty}, $units_by_name{$unit})
+  } @$stock_info;
+
+  my $content  = _format_number($sum, 2) . ' ' . $unit;
+
+  return $content;
+}
+
+sub calculate_stock_in_out {
+  my ($self, $item, $stock_info) = @_;
+
+  return "" if !$item->part || !$item->part->unit || !$item->unit;
+
+  my $sum      = sum0 map {
+    $_->unit_obj->convert_to($_->qty, $item->unit_obj)
+  } $item->delivery_order_stock_entries;
+
+  my $content  = _format_number($sum, 2);
+
+  return $content;
+}
+
+sub init_type_data {
+  SL::Controller::DeliveryOrder::TypeData->new($_[0]);
+}
+
+sub init_valid_types {
+  $_[0]->type_data->valid_types;
+}
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Controller::Order - controller for orders
+
+=head1 SYNOPSIS
+
+This is a new form to enter orders, completely rewritten with the use
+of controller and java script techniques.
+
+The aim is to provide the user a better experience and a faster workflow. Also
+the code should be more readable, more reliable and better to maintain.
+
+=head2 Key Features
+
+=over 4
+
+=item *
+
+One input row, so that input happens every time at the same place.
+
+=item *
+
+Use of pickers where possible.
+
+=item *
+
+Possibility to enter more than one item at once.
+
+=item *
+
+Item list in a scrollable area, so that the workflow buttons stay at
+the bottom.
+
+=item *
+
+Reordering item rows with drag and drop is possible. Sorting item rows is
+possible (by partnumber, description, qty, sellprice and discount for now).
+
+=item *
+
+No C<update> is necessary. All entries and calculations are managed
+with ajax-calls and the page only reloads on C<save>.
+
+=item *
+
+User can see changes immediately, because of the use of java script
+and ajax.
+
+=back
+
+=head1 CODE
+
+=head2 Layout
+
+=over 4
+
+=item * C<SL/Controller/Order.pm>
+
+the controller
+
+=item * C<template/webpages/delivery_order/form.html>
+
+main form
+
+=item * C<template/webpages/delivery_order/tabs/basic_data.html>
+
+Main tab for basic_data.
+
+This is the only tab here for now. "linked records" and "webdav" tabs are
+reused from generic code.
+
+=over 4
+
+=item * C<template/webpages/delivery_order/tabs/_business_info_row.html>
+
+For displaying information on business type
+
+=item * C<template/webpages/delivery_order/tabs/_item_input.html>
+
+The input line for items
+
+=item * C<template/webpages/delivery_order/tabs/_row.html>
+
+One row for already entered items
+
+=item * C<template/webpages/delivery_order/tabs/_tax_row.html>
+
+Displaying tax information
+
+=back
+
+=item * C<js/kivi.DeliveryOrder.js>
+
+java script functions
+
+=back
+
+=head1 TODO
+
+=over 4
+
+=item * testing
+
+=item * price sources: little symbols showing better price / better discount
+
+=item * select units in input row?
+
+=item * check for direct delivery (workflow sales order -> purchase order)
+
+=item * access rights
+
+=item * display weights
+
+=item * mtime check
+
+=item * optional client/user behaviour
+
+(transactions has to be set - department has to be set -
+ force project if enabled in client config - transport cost reminder)
+
+=back
+
+=head1 KNOWN BUGS AND CAVEATS
+
+=over 4
+
+=item *
+
+Customer discount is not displayed as a valid discount in price source popup
+(this might be a bug in price sources)
+
+(I cannot reproduce this (Bernd))
+
+=item *
+
+No indication that <shift>-up/down expands/collapses second row.
+
+=item *
+
+Inline creation of parts is not currently supported
+
+=item *
+
+Table header is not sticky in the scrolling area.
+
+=item *
+
+Sorting does not include C<position>, neither does reordering.
+
+This behavior was implemented intentionally. But we can discuss, which behavior
+should be implemented.
+
+=back
+
+=head1 To discuss / Nice to have
+
+=over 4
+
+=item *
+
+How to expand/collapse second row. Now it can be done clicking the icon or
+<shift>-up/down.
+
+=item *
+
+Possibility to select PriceSources in input row?
+
+=item *
+
+This controller uses a (changed) copy of the template for the PriceSource
+dialog. Maybe there could be used one code source.
+
+=item *
+
+Rounding-differences between this controller (PriceTaxCalculator) and the old
+form. This is not only a problem here, but also in all parts using the PTC.
+There exists a ticket and a patch. This patch should be testet.
+
+=item *
+
+An indicator, if the actual inputs are saved (like in an
+editor or on text processing application).
+
+=item *
+
+A warning when leaving the page without saveing unchanged inputs.
+
+
+=back
+
+=head1 AUTHOR
+
+Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
+
+=cut
diff --git a/SL/Controller/DeliveryOrder/TypeData.pm b/SL/Controller/DeliveryOrder/TypeData.pm
new file mode 100644 (file)
index 0000000..0650e08
--- /dev/null
@@ -0,0 +1,101 @@
+package SL::Controller::DeliveryOrder::TypeData;
+
+use strict;
+use Exporter qw(import);
+use Scalar::Util qw(weaken);
+use SL::Locale::String qw(t8);
+use SL::DB::DeliveryOrder::TypeData qw(:types :subs);
+
+my @export_types = qw(SALES_DELIVERY_ORDER_TYPE PURCHASE_DELIVERY_ORDER_TYPE SUPPLIER_DELIVERY_ORDER_TYPE RMA_DELIVERY_ORDER_TYPE);
+
+our @EXPORT_OK = (@export_types);
+our %EXPORT_TAGS = (types => \@export_types);
+
+use Rose::Object::MakeMethods::Generic scalar => [ qw(c) ];
+
+sub new {
+  my ($class, $controller) = @_;
+  my $o = bless {}, $class;
+
+  if ($controller) {
+    $o->c($controller);
+    weaken($o->{c});
+  }
+
+  return $o;
+}
+
+sub validate {
+  my ($self, $string) = @_;
+  validate_type($string);
+}
+
+sub text {
+  my ($self, $string) = @_;
+  get3($self->c->type, "text", $string);
+}
+
+sub show_menu {
+  my ($self, $string) = @_;
+  get3($self->c->type, "show_menu", $string);
+}
+
+sub workflow {
+  my ($self, $string) = @_;
+  get3($self->c->type, "workflow", $string);
+}
+
+sub properties {
+  my ($self, $string) = @_;
+  get3($self->c->type, "properties", $string);
+}
+
+sub access {
+  my ($self, $string) = @_;
+  get3($_[0]->c->type, "rights", $string);
+}
+
+sub is_quotation {
+  get3($_[0]->c->type, "properties", "is_quotation");
+}
+
+sub customervendor {
+  get3($_[0]->c->type, "properties", "customervendor");
+}
+
+sub is_customer {
+  get3($_[0]->c->type, "properties", "is_customer");
+}
+
+sub nr_key {
+  get3($_[0]->c->type, "properties", "nr_key");
+}
+
+sub transfer {
+  get3($_[0]->c->type, "properties", "transfer");
+}
+
+sub part_classification_query {
+  my ($self, $string) = @_;
+  get($self->c->type, "part_classification_query");
+}
+
+sub set_reqdate_by_type {
+  my ($self) = @_;
+
+  if (!$self->c->order->reqdate) {
+    $self->c->order->reqdate(DateTime->today_local->next_workday(extra_days => 1));
+  }
+}
+
+sub get_reqdate_by_type {
+  my ($self, $reqdate, $saved_reqdate) = @_;
+
+  if ($reqdate == $saved_reqdate) {
+    return DateTime->today_local->next_workday(extra_days => 1);
+  } else {
+    return $reqdate;
+  }
+}
+
+1;
index a94c844..6d7aaa9 100644 (file)
@@ -199,12 +199,13 @@ sub delivery_plan_query_linked_items {
       (oe.quotation = 'f' OR oe.quotation IS NULL) AND
       NOT oe.closed AND
       $oe_owner
-      oi.id NOT IN (
+      NOT EXISTS (
         SELECT from_id
         FROM record_links rl
         WHERE
-          rl.from_table ='orderitems' AND
-          rl.to_table = 'delivery_order_items'
+          rl.from_table = 'orderitems' AND
+          rl.to_table = 'delivery_order_items' AND
+          rl.from_id = oi.id
       )
 
   " ], # make emacs happy again: " ]
index 5fa5c45..ae2032f 100644 (file)
@@ -17,7 +17,7 @@ use Carp;
 use Data::Dumper;
 
 use Rose::Object::MakeMethods::Generic (
-  'scalar --get_set_init' => [ qw(models vc all_employees all_businesses) ],
+  'scalar --get_set_init' => [ qw(models vc all_employees all_businesses all_partsgroups) ],
 );
 
 __PACKAGE__->run_before(sub { $::auth->assert('delivery_value_report'); });
@@ -141,13 +141,14 @@ sub prepare_report {
 sub make_filter_summary {
   my ($self) = @_;
   my $vc     = $self->vc;
-  my ($business, $employee);
+  my ($business, $employee, $partsgroup);
 
   my $filter = $::form->{filter} || {};
   my @filter_strings;
 
-  $business = SL::DB::Business->new(id => $filter->{order}{customer}{"business_id"})->load->description if $filter->{order}{customer}{"business_id"};
-  $employee = SL::DB::Employee->new(id => $filter->{order}{employee_id})->load->name if $filter->{order}{employee_id};
+  $business   = SL::DB::Business->new(id => $filter->{order}{customer}{"business_id"})->load->description if $filter->{order}{customer}{"business_id"};
+  $employee   = SL::DB::Employee->new(id => $filter->{order}{employee_id})->load->name                    if $filter->{order}{employee_id};
+  $partsgroup = SL::DB::PartsGroup->new(id => $filter->{part}{partsgroup_id})->load->partsgroup           if $filter->{part}{partsgroup_id};
 
   my @filters = (
     [ $filter->{order}{"ordnumber:substr::ilike"},                    $::locale->text('Number')                                             ],
@@ -163,6 +164,7 @@ sub make_filter_summary {
     [ $filter->{order}{customer}{"customernumber:substr::ilike"},     $::locale->text('Customer Number')                                    ],
     [ $business,                                                      $::locale->text('Customer type')                                      ],
     [ $employee,                                                      $::locale->text('Employee')                                           ],
+    [ $partsgroup,                                                    $::locale->text('Partsgroup')                                         ],
   );
 
   # flags for with_object 'part'
@@ -217,6 +219,9 @@ sub init_all_employees {
 sub init_all_businesses {
   return SL::DB::Manager::Business->get_all_sorted;
 }
+sub init_all_partsgroups {
+  return SL::DB::Manager::PartsGroup->get_all_sorted;
+}
 
 
 sub link_to {
index 9005d79..8dacec2 100644 (file)
@@ -55,25 +55,27 @@ __PACKAGE__->run_before('check_object_params', only => [ qw(list ajax_delete aja
 # model:  base name of the rose model
 # right:  access right used for import
 my %file_types = (
-  'sales_quotation'         => { gen => 1, gltype => '',   dir =>'SalesQuotation',       model => 'Order',          right => 'import_ar'  },
-  'sales_order'             => { gen => 5, gltype => '',   dir =>'SalesOrder',           model => 'Order',          right => 'import_ar'  },
-  'sales_delivery_order'    => { gen => 1, gltype => '',   dir =>'SalesDeliveryOrder',   model => 'DeliveryOrder',  right => 'import_ar'  },
-  'invoice'                 => { gen => 1, gltype => 'ar', dir =>'SalesInvoice',         model => 'Invoice',        right => 'import_ar'  },
-  'credit_note'             => { gen => 1, gltype => '',   dir =>'CreditNote',           model => 'Invoice',        right => 'import_ar'  },
-  'request_quotation'       => { gen => 7, gltype => '',   dir =>'RequestForQuotation',  model => 'Order',          right => 'import_ap'  },
-  'purchase_order'          => { gen => 7, gltype => '',   dir =>'PurchaseOrder',        model => 'Order',          right => 'import_ap'  },
-  'purchase_delivery_order' => { gen => 7, gltype => '',   dir =>'PurchaseDeliveryOrder',model => 'DeliveryOrder',  right => 'import_ap'  },
-  'purchase_invoice'        => { gen => 6, gltype => 'ap', dir =>'PurchaseInvoice',      model => 'PurchaseInvoice',right => 'import_ap'  },
-  'vendor'                  => { gen => 0, gltype => '',   dir =>'Vendor',               model => 'Vendor',         right => 'xx'         },
-  'customer'                => { gen => 1, gltype => '',   dir =>'Customer',             model => 'Customer',       right => 'xx'         },
-  'project'                 => { gen => 0, gltype => '',   dir =>'Project',              model => 'Project',        right => 'xx'         },
-  'part'                    => { gen => 0, gltype => '',   dir =>'Part',                 model => 'Part',           right => 'xx'         },
-  'gl_transaction'          => { gen => 6, gltype => 'gl', dir =>'GeneralLedger',        model => 'GLTransaction',  right => 'import_ap'  },
-  'draft'                   => { gen => 0, gltype => '',   dir =>'Draft',                model => 'Draft',          right => 'xx'         },
-  'csv_customer'            => { gen => 1, gltype => '',   dir =>'Reports',              model => 'Customer',       right => 'xx'         },
-  'csv_vendor'              => { gen => 1, gltype => '',   dir =>'Reports',              model => 'Vendor',         right => 'xx'         },
-  'shop_image'              => { gen => 0, gltype => '',   dir =>'ShopImages',           model => 'Part',           right => 'xx'         },
-  'letter'                  => { gen => 7, gltype => '',   dir =>'Letter',               model => 'Letter',         right => 'sales_letter_edit | purchase_letter_edit' },
+  'sales_quotation'             => { gen => 1, gltype => '',   dir =>'SalesQuotation',       model => 'Order',          right => 'import_ar'  },
+  'sales_order'                 => { gen => 5, gltype => '',   dir =>'SalesOrder',           model => 'Order',          right => 'import_ar'  },
+  'sales_delivery_order'        => { gen => 1, gltype => '',   dir =>'SalesDeliveryOrder',   model => 'DeliveryOrder',  right => 'import_ar'  },
+  'invoice'                     => { gen => 1, gltype => 'ar', dir =>'SalesInvoice',         model => 'Invoice',        right => 'import_ar'  },
+  'invoice_for_advance_payment' => { gen => 1, gltype => 'ar', dir =>'SalesInvoice',         model => 'Invoice',        right => 'import_ar'  },
+  'final_invoice'               => { gen => 1, gltype => 'ar', dir =>'SalesInvoice',         model => 'Invoice',        right => 'import_ar'  },
+  'credit_note'                 => { gen => 1, gltype => '',   dir =>'CreditNote',           model => 'Invoice',        right => 'import_ar'  },
+  'request_quotation'           => { gen => 7, gltype => '',   dir =>'RequestForQuotation',  model => 'Order',          right => 'import_ap'  },
+  'purchase_order'              => { gen => 7, gltype => '',   dir =>'PurchaseOrder',        model => 'Order',          right => 'import_ap'  },
+  'purchase_delivery_order'     => { gen => 7, gltype => '',   dir =>'PurchaseDeliveryOrder',model => 'DeliveryOrder',  right => 'import_ap'  },
+  'purchase_invoice'            => { gen => 6, gltype => 'ap', dir =>'PurchaseInvoice',      model => 'PurchaseInvoice',right => 'import_ap'  },
+  'vendor'                      => { gen => 0, gltype => '',   dir =>'Vendor',               model => 'Vendor',         right => 'xx'         },
+  'customer'                    => { gen => 1, gltype => '',   dir =>'Customer',             model => 'Customer',       right => 'xx'         },
+  'project'                     => { gen => 0, gltype => '',   dir =>'Project',              model => 'Project',        right => 'xx'         },
+  'part'                        => { gen => 0, gltype => '',   dir =>'Part',                 model => 'Part',           right => 'xx'         },
+  'gl_transaction'              => { gen => 6, gltype => 'gl', dir =>'GeneralLedger',        model => 'GLTransaction',  right => 'import_ap'  },
+  'draft'                       => { gen => 0, gltype => '',   dir =>'Draft',                model => 'Draft',          right => 'xx'         },
+  'csv_customer'                => { gen => 1, gltype => '',   dir =>'Reports',              model => 'Customer',       right => 'xx'         },
+  'csv_vendor'                  => { gen => 1, gltype => '',   dir =>'Reports',              model => 'Vendor',         right => 'xx'         },
+  'shop_image'                  => { gen => 0, gltype => '',   dir =>'ShopImages',           model => 'Part',           right => 'xx'         },
+  'letter'                      => { gen => 7, gltype => '',   dir =>'Letter',               model => 'Letter',         right => 'sales_letter_edit | purchase_letter_edit' },
 );
 
 #--- 4 locale ---#
@@ -402,26 +404,21 @@ sub _delete_all {
 
 sub _do_list {
   my ($self, $json) = @_;
+
   my @files;
+  my @object_types = ($self->object_type);
   if ( $self->file_type eq 'document' ) {
-    my @object_types;
-    push @object_types, $self->object_type;
     push @object_types, qw(dunning1 dunning2 dunning3 dunning_invoice dunning_orig_invoice) if $self->object_type eq 'invoice'; # hardcoded object types?
-    @files = SL::File->get_all_versions(object_id   => $self->object_id,
-                                        object_type => \@object_types,
-                                        file_type   => $self->file_type,
-                                       );
-
-  }
-  elsif ( $self->file_type eq 'attachment' || $self->file_type eq 'image' ) {
-    @files   = SL::File->get_all(object_id   => $self->object_id,
-                                 object_type => $self->object_type,
-                                 file_type   => $self->file_type,
-                                );
   }
+  @files = SL::File->get_all_versions(object_id   => $self->object_id,
+                                      object_type => \@object_types,
+                                      file_type   => $self->file_type,
+                                     );
+
   $self->files(\@files);
 
-  $_->{thumbnail} = _create_thumbnail($_) for @files;
+  $_->{thumbnail}     = _create_thumbnail($_)                     for @files;
+  $_->{version_count} = SL::File->get_version_count(id => $_->id) for @files;
 
   if($self->object_type eq 'shop_image'){
     $self->js
@@ -679,7 +676,12 @@ sub _convert_pdf_to_png {
 
   my $size    = $params{size} // 64;
   my $sfile   = SL::SessionFile::Random->new();
-  my $command = 'pdftoppm -singlefile -scale-to ' . $size . ' -png' . ' ' . $filename . ' ' . $sfile->file_name;
+  unless (-f $filename) {
+    $::lxdebug->message(LXDebug::WARN(), "_convert_pdf_to_png failed, no file found: $filename");
+    return;
+  }
+  # quotemeta for storno case "storno\ zu\ 1020" *nix only
+  my $command = 'pdftoppm -singlefile -scale-to ' . $size . ' -png' . ' ' . quotemeta($filename) . ' ' . $sfile->file_name;
 
   if (system($command) == -1) {
     $::lxdebug->message(LXDebug::WARN(), "SL::File::_convert_pdf_to_png: system call failed: " . $ERRNO);
@@ -687,6 +689,7 @@ sub _convert_pdf_to_png {
   }
   if ($CHILD_ERROR) {
     $::lxdebug->message(LXDebug::WARN(), "SL::File::_convert_pdf_to_png: pdftoppm failed with error code: " . ($CHILD_ERROR >> 8));
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_convert_pdf_to_png: File: $filename");
     return;
   }
 
index 18561e0..a2497f5 100644 (file)
@@ -20,7 +20,7 @@ my %object_loader = (
   sales_order     => [ "SL::DB::Order", [ sales => 1, quotation => 0 ] ],
   sales_quotation => [ "SL::DB::Order", [ sales => 1, quotation => 1 ] ],
   purchase_order  => [ "SL::DB::Order", [ sales => 0, quotation => 1 ] ],
-  sales_delivery_order => [ "SL::DB::DeliveryOrder", [ is_sales => 1 ] ],
+  sales_delivery_order => [ "SL::DB::DeliveryOrder", [ order_type => 'sales_delivery_order' ] ],
 );
 
 
index 1324638..a4c11f6 100644 (file)
@@ -394,7 +394,7 @@ sub make_row_result {
        $row->{outcorrection}->{data} - $row->{incorrection}->{data};
   $row->{averconsumed}->{data} = $row->{consumed}->{data}*30/$days ;
   map { $row->{$_}->{data} = $form->format_amount($myconfig,$row->{$_}->{data},2); } $self->getnumcolumns();
-  $row->{partnumber}->{link} = 'controller.pl?action=Part/edit&part.id' . $partid;
+  $row->{partnumber}->{link} = 'controller.pl?action=Part/edit&part.id=' . $partid;
 }
 
 sub action_stock {
index 4da3e19..4faf452 100644 (file)
@@ -620,6 +620,8 @@ sub setup_load_letter_draft_action_bar {
 sub setup_display_action_bar {
   my ($self, %params) = @_;
 
+  my $vc = $self->is_sales ? 'customer' : 'vendor'; # needed for show_email_dialog
+
   for my $bar ($::request->layout->get('actionbar')) {
     $bar->add(
       action => [
@@ -655,7 +657,7 @@ sub setup_display_action_bar {
         ],
         action => [
           t8('E-mail'),
-          call     => [ 'kivi.SalesPurchase.show_email_dialog', 'Letter/send_email' ],
+          call     => [ 'kivi.SalesPurchase.show_email_dialog', 'Letter/send_email', $vc, '#letter_' . $vc . '_id' ],
           disabled => !$self->letter->id ? t8('The object has not been saved yet.') : undef,
         ],
       ],
index acc300e..626a663 100644 (file)
@@ -19,6 +19,7 @@ use SL::Helper::File qw(store_pdf append_general_pdf_attachments doc_storage_ena
 use SL::Helper::Flash;
 use SL::Locale::String;
 use SL::SessionFile;
+use SL::ARAP;
 use SL::System::TaskServer;
 use Rose::Object::MakeMethods::Generic
 (
@@ -57,6 +58,7 @@ sub action_create_invoices {
   }
 
   my $db = SL::DB::Invoice->new->db;
+  my $dbh = $db->dbh;
   my @invoices;
   my @already_closed_delivery_orders;
 
@@ -73,6 +75,11 @@ sub action_create_invoices {
 
       } else {
         my $invoice = $delivery_order->convert_to_invoice() || die $db->error;
+
+        ARAP->close_orders_if_billed('dbh'     => $dbh,
+                                     'arap_id' => $invoice->id,
+                                     'table'   => 'ar',);
+
         push @invoices, $invoice;
       }
     }
@@ -83,6 +90,23 @@ sub action_create_invoices {
     $::form->error($db->error);
   }
 
+  foreach my $invoice( @invoices ) {
+    # update shop status
+    my @linked_shop_orders = $invoice->linked_records(
+      from      => 'ShopOrder',
+      via       => [ 'DeliveryOrder', 'Order' ],
+    );
+    #if (scalar @linked_shop_orders[0][0] >= 1){
+      #do update
+    my $shop_order = $linked_shop_orders[0][0];
+    if ($shop_order){
+    require SL::Shop;
+      my $shop_config = SL::DB::Manager::Shop->get_first( query => [ id => $shop_order->shop_id ] );
+      my $shop = SL::Shop->new( config => $shop_config );
+      $shop->connector->set_orderstatus($shop_order->shop_trans_id, "completed");
+    }
+  }
+
   my $key = sprintf('%d-%d', Time::HiRes::gettimeofday());
   $::auth->set_session_value("MassInvoiceCreatePrint::ids-${key}" => [ map { $_->id } @invoices ]);
 
index 03a8917..99e20ff 100644 (file)
@@ -51,10 +51,9 @@ sub action_showmap {
        $::lxdebug->enter_sub;
        my ($self) = @_;
        
-       # call model
+       # call model -> diese Zeile ist fraglich, war ein Konflikt
        $self->{data} = DB::MebilMapping::getMappings($::form->get_standard_dbh);
        
-       
        $::form->{title} = $::locale->text('Mebil Map');
 
        my $sql = "SELECT fromacc,typ,toacc from mebil_mapping order by ordering";
index 0953811..faf2ffa 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use parent qw(SL::Controller::Base);
 
 use SL::Helper::Flash qw(flash_later);
+use SL::HTML::Util;
 use SL::Presenter::Tag qw(select_tag hidden_tag div_tag);
 use SL::Locale::String qw(t8);
 use SL::SessionFile::Random;
@@ -13,6 +14,8 @@ use SL::File;
 use SL::MIME;
 use SL::Util qw(trim);
 use SL::YAML;
+use SL::DB::AdditionalBillingAddress;
+use SL::DB::AuthUser;
 use SL::DB::History;
 use SL::DB::Order;
 use SL::DB::Default;
@@ -21,14 +24,17 @@ use SL::DB::Part;
 use SL::DB::PartClassification;
 use SL::DB::PartsGroup;
 use SL::DB::Printer;
+use SL::DB::Note;
 use SL::DB::Language;
 use SL::DB::RecordLink;
+use SL::DB::RequirementSpec;
 use SL::DB::Shipto;
 use SL::DB::Translation;
 
 use SL::Helper::CreatePDF qw(:all);
 use SL::Helper::PrintOptions;
 use SL::Helper::ShippedQty;
+use SL::Helper::UserPreferences::DisplayPreferences;
 use SL::Helper::UserPreferences::PositionsScrollbar;
 use SL::Helper::UserPreferences::UpdatePositions;
 
@@ -52,12 +58,15 @@ use Rose::Object::MakeMethods::Generic
 # safety
 __PACKAGE__->run_before('check_auth');
 
+__PACKAGE__->run_before('check_auth_for_edit',
+                        except => [ qw(edit show_customer_vendor_details_dialog price_popup load_second_rows) ]);
+
 __PACKAGE__->run_before('recalc',
-                        only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_ap_transaction
+                        only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_invoice_for_advance_payment save_and_final_invoice save_and_ap_transaction
                                      print send_email) ]);
 
 __PACKAGE__->run_before('get_unalterable_data',
-                        only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_ap_transaction
+                        only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_invoice_for_advance_payment save_and_final_invoice save_and_ap_transaction
                                      print send_email) ]);
 
 #
@@ -190,11 +199,19 @@ sub action_save {
            : '';
   flash_later('info', $text);
 
-  my @redirect_params = (
-    action => 'edit',
-    type   => $self->type,
-    id     => $self->order->id,
-  );
+  my @redirect_params;
+  if ($::form->{back_to_caller}) {
+    @redirect_params = $::form->{callback} ? ($::form->{callback})
+                                           : (controller => 'LoginScreen', action => 'user_login');
+
+  } else {
+    @redirect_params = (
+      action   => 'edit',
+      type     => $self->type,
+      id       => $self->order->id,
+      callback => $::form->{callback},
+    );
+  }
 
   $self->redirect_to(@redirect_params);
 }
@@ -243,6 +260,10 @@ sub action_save_as_new {
   # Update employee
   $new_attrs{employee}  = SL::DB::Manager::Employee->current;
 
+  # Warn on obsolete items
+  my @obsolete_positions = map { $_->position } grep { $_->part->obsolete } @{ $order->items_sorted };
+  flash_later('warning', t8('This record containts obsolete items at position #1', join ', ', @obsolete_positions)) if @obsolete_positions;
+
   # Create new record from current one
   $self->order(SL::DB::Order->new_from($order, destination_type => $order->type, attributes => \%new_attrs));
 
@@ -270,6 +291,12 @@ sub action_print {
 
   $self->js_reset_order_and_item_ids_after_save;
 
+  my $redirect_url = $self->url_for(
+    action => 'edit',
+    type   => $self->type,
+    id     => $self->order->id,
+  );
+
   my $format      = $::form->{print_options}->{format};
   my $media       = $::form->{print_options}->{media};
   my $formname    = $::form->{print_options}->{formname};
@@ -277,14 +304,16 @@ sub action_print {
   my $groupitems  = $::form->{print_options}->{groupitems};
   my $printer_id  = $::form->{print_options}->{printer_id};
 
-  # only pdf and opendocument by now
-  if (none { $format eq $_ } qw(pdf opendocument opendocument_pdf)) {
-    return $self->js->flash('error', t8('Format \'#1\' is not supported yet/anymore.', $format))->render;
+  # only PDF, OpenDocument & HTML for now
+  if (none { $format eq $_ } qw(pdf opendocument opendocument_pdf html)) {
+    flash_later('error', t8('Format \'#1\' is not supported yet/anymore.', $format));
+    return $self->js->redirect_to($redirect_url)->render;
   }
 
   # only screen or printer by now
   if (none { $media eq $_ } qw(screen printer)) {
-    return $self->js->flash('error', t8('Media \'#1\' is not supported yet/anymore.', $media))->render;
+    flash_later('error', t8('Media \'#1\' is not supported yet/anymore.', $media));
+    return $self->js->redirect_to($redirect_url)->render;
   }
 
   # create a form for generate_attachment_filename
@@ -294,25 +323,27 @@ sub action_print {
   $form->{format}           = $format;
   $form->{formname}         = $formname;
   $form->{language}         = '_' . $self->order->language->template_code if $self->order->language;
-  my $pdf_filename          = $form->generate_attachment_filename();
-
-  my $pdf;
-  my @errors = generate_pdf($self->order, \$pdf, { format     => $format,
-                                                   formname   => $formname,
-                                                   language   => $self->order->language,
-                                                   printer_id => $printer_id,
-                                                   groupitems => $groupitems });
+  my $doc_filename          = $form->generate_attachment_filename();
+
+  my $doc;
+  my @errors = $self->generate_doc(\$doc, { media      => $media,
+                                            format     => $format,
+                                            formname   => $formname,
+                                            language   => $self->order->language,
+                                            printer_id => $printer_id,
+                                            groupitems => $groupitems });
   if (scalar @errors) {
-    return $self->js->flash('error', t8('Conversion to PDF failed: #1', $errors[0]))->render;
+    flash_later('error', t8('Generating the document failed: #1', $errors[0]));
+    return $self->js->redirect_to($redirect_url)->render;
   }
 
   if ($media eq 'screen') {
     # screen/download
-    $self->js->flash('info', t8('The PDF has been created'));
+    flash_later('info', t8('The document has been created.'));
     $self->send_file(
-      \$pdf,
-      type         => SL::MIME->mime_type_from_ext($pdf_filename),
-      name         => $pdf_filename,
+      \$doc,
+      type         => SL::MIME->mime_type_from_ext($doc_filename),
+      name         => $doc_filename,
       js_no_render => 1,
     );
 
@@ -321,23 +352,22 @@ sub action_print {
     my $printer_id = $::form->{print_options}->{printer_id};
     SL::DB::Printer->new(id => $printer_id)->load->print_document(
       copies  => $copies,
-      content => $pdf,
+      content => $doc,
     );
 
-    $self->js->flash('info', t8('The PDF has been printed'));
+    flash_later('info', t8('The document has been printed.'));
   }
 
-  my @warnings = store_pdf_to_webdav_and_filemanagement($self->order, $pdf, $pdf_filename);
+  my @warnings = $self->store_doc_to_webdav_and_filemanagement($doc, $doc_filename, $formname);
   if (scalar @warnings) {
-    $self->js->flash('warning', $_) for @warnings;
+    flash_later('warning', $_) for @warnings;
   }
 
   $self->save_history('PRINTED');
 
-  $self->js
-    ->run('kivi.ActionBar.setEnabled', '#save_and_email_action')
-    ->render;
+  $self->js->redirect_to($redirect_url)->render;
 }
+
 sub action_preview_pdf {
   my ($self) = @_;
 
@@ -349,6 +379,12 @@ sub action_preview_pdf {
 
   $self->js_reset_order_and_item_ids_after_save;
 
+  my $redirect_url = $self->url_for(
+    action => 'edit',
+    type   => $self->type,
+    id     => $self->order->id,
+  );
+
   my $format      = 'pdf';
   my $media       = 'screen';
   my $formname    = $self->type;
@@ -364,22 +400,29 @@ sub action_preview_pdf {
   my $pdf_filename          = $form->generate_attachment_filename();
 
   my $pdf;
-  my @errors = generate_pdf($self->order, \$pdf, { format     => $format,
-                                                   formname   => $formname,
-                                                   language   => $self->order->language,
-                                                 });
+  my @errors = $self->generate_doc(\$pdf, { media      => $media,
+                                            format     => $format,
+                                            formname   => $formname,
+                                            language   => $self->order->language,
+                                          });
   if (scalar @errors) {
-    return $self->js->flash('error', t8('Conversion to PDF failed: #1', $errors[0]))->render;
+    flash_later('error', t8('Conversion to PDF failed: #1', $errors[0]));
+    return $self->js->redirect_to($redirect_url)->render;
   }
+
   $self->save_history('PREVIEWED');
-  $self->js->flash('info', t8('The PDF has been previewed'));
+
+  flash_later('info', t8('The PDF has been previewed'));
+
   # screen/download
   $self->send_file(
     \$pdf,
     type         => SL::MIME->mime_type_from_ext($pdf_filename),
     name         => $pdf_filename,
-    js_no_render => 0,
+    js_no_render => 1,
   );
+
+  $self->js->redirect_to($redirect_url)->render;
 }
 
 # open the email dialog
@@ -393,6 +436,8 @@ sub action_save_and_show_email_dialog {
     return $self->js->render();
   }
 
+  $self->js_reset_order_and_item_ids_after_save;
+
   my $cv_method = $self->cv;
 
   if (!$self->order->$cv_method) {
@@ -423,13 +468,22 @@ sub action_save_and_show_email_dialog {
   $email_form->{js_send_function}    = 'kivi.Order.send_email()';
 
   my %files = $self->get_files_for_email_dialog();
-  $self->{all_employees} = SL::DB::Manager::Employee->get_all(query => [ deleted => 0 ]);
+
+  my @employees_with_email = grep {
+    my $user = SL::DB::Manager::AuthUser->find_by(login => $_->login);
+    $user && !!trim($user->get_config_value('email'));
+  } @{ SL::DB::Manager::Employee->get_all_sorted(query => [ deleted => 0 ]) };
+
+
+  my $all_partner_email_addresses = $self->order->customervendor->get_all_email_addresses();
+
   my $dialog_html = $self->render('common/_send_email_dialog', { output => 0 },
-                                  email_form  => $email_form,
-                                  show_bcc    => $::auth->assert('email_bcc', 'may fail'),
-                                  FILES       => \%files,
-                                  is_customer => $self->cv eq 'customer',
-                                  ALL_EMPLOYEES => $self->{all_employees},
+                                  email_form    => $email_form,
+                                  show_bcc      => $::auth->assert('email_bcc', 'may fail'),
+                                  FILES         => \%files,
+                                  is_customer   => $self->cv eq 'customer',
+                                  ALL_EMPLOYEES => \@employees_with_email,
+                                  ALL_PARTNER_EMAIL_ADDRESSES => $all_partner_email_addresses,
   );
 
   $self->js
@@ -455,6 +509,12 @@ sub action_send_email {
   $self->js_reset_order_and_item_ids_after_save;
 
   my $email_form  = delete $::form->{email_form};
+
+  if ($email_form->{additional_to}) {
+    $email_form->{to} = join ', ', grep { $_ } $email_form->{to}, @{$email_form->{additional_to}};
+    delete $email_form->{additional_to};
+  }
+
   my %field_names = (to => 'email');
 
   $::form->{ $field_names{$_} // $_ } = $email_form->{$_} for keys %{ $email_form };
@@ -466,25 +526,36 @@ sub action_send_email {
   $::form->{$_}     = $::form->{print_options}->{$_} for keys %{ $::form->{print_options} };
   $::form->{media}  = 'email';
 
-  if (($::form->{attachment_policy} // '') !~ m{^(?:old_file|no_file)$}) {
-    my $pdf;
-    my @errors = generate_pdf($self->order, \$pdf, {media      => $::form->{media},
-                                                    format     => $::form->{print_options}->{format},
-                                                    formname   => $::form->{print_options}->{formname},
-                                                    language   => $self->order->language,
-                                                    printer_id => $::form->{print_options}->{printer_id},
-                                                    groupitems => $::form->{print_options}->{groupitems}});
+  $::form->{attachment_policy} //= '';
+
+  # Is an old file version available?
+  my $attfile;
+  if ($::form->{attachment_policy} eq 'old_file') {
+    $attfile = SL::File->get_all(object_id     => $self->order->id,
+                                 object_type   => $self->type,
+                                 file_type     => 'document',
+                                 print_variant => $::form->{formname});
+  }
+
+  if ($::form->{attachment_policy} ne 'no_file' && !($::form->{attachment_policy} eq 'old_file' && $attfile)) {
+    my $doc;
+    my @errors = $self->generate_doc(\$doc, {media      => $::form->{media},
+                                             format     => $::form->{print_options}->{format},
+                                             formname   => $::form->{print_options}->{formname},
+                                             language   => $self->order->language,
+                                             printer_id => $::form->{print_options}->{printer_id},
+                                             groupitems => $::form->{print_options}->{groupitems}});
     if (scalar @errors) {
-      return $self->js->flash('error', t8('Conversion to PDF failed: #1', $errors[0]))->render($self);
+      return $self->js->flash('error', t8('Generating the document failed: #1', $errors[0]))->render($self);
     }
 
-    my @warnings = store_pdf_to_webdav_and_filemanagement($self->order, $pdf, $::form->{attachment_filename});
+    my @warnings = $self->store_doc_to_webdav_and_filemanagement($doc, $::form->{attachment_filename}, $::form->{formname});
     if (scalar @warnings) {
       flash_later('warning', $_) for @warnings;
     }
 
     my $sfile = SL::SessionFile::Random->new(mode => "w");
-    $sfile->fh->print($pdf);
+    $sfile->fh->print($doc);
     $sfile->fh->close;
 
     $::form->{tmpfile} = $sfile->file_name;
@@ -492,20 +563,22 @@ sub action_send_email {
   }
 
   $::form->{id} = $self->order->id; # this is used in SL::Mailer to create a linked record to the mail
-  $::form->send_email(\%::myconfig, 'pdf');
+  $::form->send_email(\%::myconfig, $::form->{print_options}->{format});
 
-  # internal notes
-  my $intnotes = $self->order->intnotes;
-  $intnotes   .= "\n\n" if $self->order->intnotes;
-  $intnotes   .= t8('[email]')                                                                                        . "\n";
-  $intnotes   .= t8('Date')       . ": " . $::locale->format_date_object(DateTime->now_local, precision => 'seconds') . "\n";
-  $intnotes   .= t8('To (email)') . ": " . $::form->{email}                                                           . "\n";
-  $intnotes   .= t8('Cc')         . ": " . $::form->{cc}                                                              . "\n"    if $::form->{cc};
-  $intnotes   .= t8('Bcc')        . ": " . $::form->{bcc}                                                             . "\n"    if $::form->{bcc};
-  $intnotes   .= t8('Subject')    . ": " . $::form->{subject}                                                         . "\n\n";
-  $intnotes   .= t8('Message')    . ": " . $::form->{message};
+  # internal notes unless no email journal
+  unless ($::instance_conf->get_email_journal) {
+    my $intnotes = $self->order->intnotes;
+    $intnotes   .= "\n\n" if $self->order->intnotes;
+    $intnotes   .= t8('[email]')                                                                                        . "\n";
+    $intnotes   .= t8('Date')       . ": " . $::locale->format_date_object(DateTime->now_local, precision => 'seconds') . "\n";
+    $intnotes   .= t8('To (email)') . ": " . $::form->{email}                                                           . "\n";
+    $intnotes   .= t8('Cc')         . ": " . $::form->{cc}                                                              . "\n"    if $::form->{cc};
+    $intnotes   .= t8('Bcc')        . ": " . $::form->{bcc}                                                             . "\n"    if $::form->{bcc};
+    $intnotes   .= t8('Subject')    . ": " . $::form->{subject}                                                         . "\n\n";
+    $intnotes   .= t8('Message')    . ": " . SL::HTML::Util->strip($::form->{message});
 
-  $self->order->update_attributes(intnotes => $intnotes);
+    $self->order->update_attributes(intnotes => $intnotes);
+  }
 
   $self->save_history('MAILED');
 
@@ -538,9 +611,32 @@ sub action_show_periodic_invoices_config_dialog {
                                                                                 language_id      => $::form->{language_id},
                                                                                 translation_type =>"preset_text_periodic_invoices_email_subject"),
                                                    email_body              => GenericTranslations->get(
+                                                                                language_id      => $::form->{language_id},
+                                                                                translation_type => "salutation_general")
+                                                                            . GenericTranslations->get(
+                                                                                language_id      => $::form->{language_id},
+                                                                                translation_type => "salutation_punctuation_mark") . "\n\n"
+                                                                            . GenericTranslations->get(
                                                                                 language_id      => $::form->{language_id},
                                                                                 translation_type =>"preset_text_periodic_invoices_email_body"),
   );
+  # for older configs, replace email preset text if not yet set.
+  $config->email_subject(GenericTranslations->get(
+                                              language_id      => $::form->{language_id},
+                                              translation_type =>"preset_text_periodic_invoices_email_subject")
+                        ) unless $config->email_subject;
+
+  $config->email_body(GenericTranslations->get(
+                                              language_id      => $::form->{language_id},
+                                              translation_type => "salutation_general")
+                    . GenericTranslations->get(
+                                              language_id      => $::form->{language_id},
+                                              translation_type => "salutation_punctuation_mark") . "\n\n"
+                    . GenericTranslations->get(
+                                              language_id      => $::form->{language_id},
+                                              translation_type =>"preset_text_periodic_invoices_email_body")
+                     ) unless $config->email_body;
+
   $config->periodicity('m')             if none { $_ eq $config->periodicity             }       @SL::DB::PeriodicInvoicesConfig::PERIODICITIES;
   $config->order_value_periodicity('p') if none { $_ eq $config->order_value_periodicity } ('p', @SL::DB::PeriodicInvoicesConfig::ORDER_VALUE_PERIODICITIES);
 
@@ -634,6 +730,16 @@ sub action_save_and_delivery_order {
   );
 }
 
+sub action_save_and_supplier_delivery_order {
+  my ($self) = @_;
+
+  $self->save_and_redirect_to(
+    controller => 'controller.pl',
+    action     => 'DeliveryOrder/add_from_order',
+    type       => 'supplier_delivery_order',
+  );
+}
+
 # save the order and redirect to the frontend subroutine for a new
 # invoice
 sub action_save_and_invoice {
@@ -645,6 +751,26 @@ sub action_save_and_invoice {
   );
 }
 
+sub action_save_and_invoice_for_advance_payment {
+  my ($self) = @_;
+
+  $self->save_and_redirect_to(
+    controller       => 'oe.pl',
+    action           => 'oe_invoice_from_order',
+    new_invoice_type => 'invoice_for_advance_payment',
+  );
+}
+
+sub action_save_and_final_invoice {
+  my ($self) = @_;
+
+  $self->save_and_redirect_to(
+    controller       => 'oe.pl',
+    action           => 'oe_invoice_from_order',
+    new_invoice_type => 'final_invoice',
+  );
+}
+
 # workflow from sales order to sales quotation
 sub action_sales_quotation {
   $_[0]->workflow_sales_or_request_for_quotation();
@@ -698,20 +824,26 @@ sub action_customer_vendor_changed {
     $self->js->hide('#shipto_selection');
   }
 
+  if ($cv_method eq 'customer') {
+    my $show_hide = scalar @{ $self->order->customer->additional_billing_addresses } > 0 ? 'show' : 'hide';
+    $self->js->$show_hide('#billing_address_row');
+  }
+
   $self->js->val( '#order_salesman_id',      $self->order->salesman_id)        if $self->order->is_sales;
 
   $self->js
-    ->replaceWith('#order_cp_id',            $self->build_contact_select)
-    ->replaceWith('#order_shipto_id',        $self->build_shipto_select)
-    ->replaceWith('#shipto_inputs  ',        $self->build_shipto_inputs)
-    ->replaceWith('#business_info_row',      $self->build_business_info_row)
-    ->val(        '#order_taxzone_id',       $self->order->taxzone_id)
-    ->val(        '#order_taxincluded',      $self->order->taxincluded)
-    ->val(        '#order_currency_id',      $self->order->currency_id)
-    ->val(        '#order_payment_id',       $self->order->payment_id)
-    ->val(        '#order_delivery_term_id', $self->order->delivery_term_id)
-    ->val(        '#order_intnotes',         $self->order->intnotes)
-    ->val(        '#order_language_id',      $self->order->$cv_method->language_id)
+    ->replaceWith('#order_cp_id',              $self->build_contact_select)
+    ->replaceWith('#order_shipto_id',          $self->build_shipto_select)
+    ->replaceWith('#shipto_inputs  ',          $self->build_shipto_inputs)
+    ->replaceWith('#order_billing_address_id', $self->build_billing_address_select)
+    ->replaceWith('#business_info_row',        $self->build_business_info_row)
+    ->val(        '#order_taxzone_id',         $self->order->taxzone_id)
+    ->val(        '#order_taxincluded',        $self->order->taxincluded)
+    ->val(        '#order_currency_id',        $self->order->currency_id)
+    ->val(        '#order_payment_id',         $self->order->payment_id)
+    ->val(        '#order_delivery_term_id',   $self->order->delivery_term_id)
+    ->val(        '#order_intnotes',           $self->order->intnotes)
+    ->val(        '#order_language_id',        $self->order->$cv_method->language_id)
     ->focus(      '#order_' . $self->cv . '_id')
     ->run('kivi.Order.update_exchangerate');
 
@@ -741,6 +873,11 @@ sub action_show_customer_vendor_details_dialog {
   $details{payment_terms}       = $cv->payment->description       if $cv->payment;
   $details{pricegroup}          = $cv->pricegroup->pricegroup     if $is_customer && $cv->pricegroup;
 
+  if ($is_customer) {
+    foreach my $entry (@{ $cv->additional_billing_addresses }) {
+      push @{ $details{ADDITIONAL_BILLING_ADDRESSES} },   { map { $_ => $entry->$_ } @{$entry->meta->columns} };
+    }
+  }
   foreach my $entry (@{ $cv->shipto }) {
     push @{ $details{SHIPTO} },   { map { $_ => $entry->$_ } @{$entry->meta->columns} };
   }
@@ -773,6 +910,34 @@ sub action_unit_changed {
   $self->js->render();
 }
 
+# update item input row when a part ist picked
+sub action_update_item_input_row {
+  my ($self) = @_;
+
+  delete $::form->{add_item}->{$_} for qw(create_part_type sellprice_as_number discount_as_percent);
+
+  my $form_attr = $::form->{add_item};
+
+  return unless $form_attr->{parts_id};
+
+  my $record       = $self->order;
+  my $item         = SL::DB::OrderItem->new(%$form_attr);
+  $item->unit($item->part->unit);
+
+  my ($price_src, $discount_src) = get_best_price_and_discount_source($record, $item, 0);
+
+  $self->js
+    ->val     ('#add_item_unit',                $item->unit)
+    ->val     ('#add_item_description',         $item->part->description)
+    ->val     ('#add_item_sellprice_as_number', '')
+    ->attr    ('#add_item_sellprice_as_number', 'placeholder', $price_src->price_as_number)
+    ->attr    ('#add_item_sellprice_as_number', 'title',       $price_src->source_description)
+    ->val     ('#add_item_discount_as_percent', '')
+    ->attr    ('#add_item_discount_as_percent', 'placeholder', $discount_src->discount_as_percent)
+    ->attr    ('#add_item_discount_as_percent', 'title',       $discount_src->source_description)
+    ->render;
+}
+
 # add an item row for a new item entered in the input row
 sub action_add_item {
   my ($self) = @_;
@@ -840,6 +1005,8 @@ sub action_add_item {
 
   $self->js
     ->val('.add_item_input', '')
+    ->attr('.add_item_input', 'placeholder', '')
+    ->attr('.add_item_input', 'title', '')
     ->run('kivi.Order.init_row_handlers')
     ->run('kivi.Order.renumber_positions')
     ->focus('#add_item_parts_id_name');
@@ -993,11 +1160,11 @@ sub action_create_part {
   flash_later('info', t8('You are adding a new part while you are editing another document. You will be redirected to your document when saving the new part or aborting this form.'));
 
   my @redirect_params = (
-    controller => 'Part',
-    action     => 'add',
-    part_type  => $::form->{add_item}->{create_part_type},
-    callback   => $callback,
-    show_abort => 1,
+    controller    => 'Part',
+    action        => 'add',
+    part_type     => $::form->{add_item}->{create_part_type},
+    callback      => $callback,
+    inline_create => 1,
   );
 
   $self->redirect_to(@redirect_params);
@@ -1066,27 +1233,18 @@ sub action_update_row_from_master_data {
     $item->description($texts->{description});
     $item->longdescription($texts->{longdescription});
 
-    my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order);
-
-    my $price_src;
-    if ($item->part->is_assortment) {
-    # add assortment items with price 0, as the components carry the price
-      $price_src = $price_source->price_from_source("");
-      $price_src->price(0);
-    } else {
-      $price_src = $price_source->best_price
-                 ? $price_source->best_price
-                 : $price_source->price_from_source("");
-      $price_src->price($::form->round_amount($price_src->price / $self->order->exchangerate, 5)) if $self->order->exchangerate;
-      $price_src->price(0) if !$price_source->best_price;
-    }
-
+    my ($price_src, $discount_src) = get_best_price_and_discount_source($self->order, $item, 1);
 
     $item->sellprice($price_src->price);
     $item->active_price_source($price_src);
+    $item->discount($discount_src->discount);
+    $item->active_discount_source($discount_src);
+
+    my $price_editable = $self->order->is_sales ? $::auth->assert('sales_edit_prices', 1) : $::auth->assert('purchase_edit_prices', 1);
 
     $self->js
-      ->run('kivi.Order.update_sellprice', $item_id, $item->sellprice_as_number)
+      ->run('kivi.Order.set_price_and_source_text',    $item_id, $price_src   ->source, $price_src   ->source_description, $item->sellprice_as_number, $price_editable)
+      ->run('kivi.Order.set_discount_and_source_text', $item_id, $discount_src->source, $discount_src->source_description, $item->discount_as_percent, $price_editable)
       ->html('.row_entry:has(#item_' . $item_id . ') [name = "partnumber"] a', $item->part->partnumber)
       ->val ('.row_entry:has(#item_' . $item_id . ') [name = "order.orderitems[].description"]', $item->description)
       ->val ('.row_entry:has(#item_' . $item_id . ') [name = "order.orderitems[].longdescription"]', $item->longdescription);
@@ -1104,6 +1262,58 @@ sub action_update_row_from_master_data {
   $self->js->render();
 }
 
+sub action_save_phone_note {
+  my ($self) = @_;
+
+  if (!$::form->{phone_note}->{subject} || !$::form->{phone_note}->{body}) {
+    return $self->js->flash('error', t8('Phone note needs a subject and a body.'))->render;
+  }
+
+  my $phone_note;
+  if ($::form->{phone_note}->{id}) {
+    $phone_note = first { $_->id == $::form->{phone_note}->{id} } @{$self->order->phone_notes};
+    return $self->js->flash('error', t8('Phone note not found for this order.'))->render if !$phone_note;
+  }
+
+  $phone_note = SL::DB::Note->new() if !$phone_note;
+  my $is_new  = !$phone_note->id;
+
+  $phone_note->assign_attributes(%{ $::form->{phone_note} },
+                                 trans_id     => $self->order->id,
+                                 trans_module => 'oe',
+                                 employee     => SL::DB::Manager::Employee->current);
+
+  $phone_note->save;
+  $self->order(SL::DB::Order->new(id => $self->order->id)->load);
+
+  my $tab_as_html = $self->p->render('order/tabs/phone_notes', SELF => $self);
+
+  return $self->js
+    ->replaceWith('#phone-notes', $tab_as_html)
+    ->html('#num_phone_notes', (scalar @{$self->order->phone_notes}) ? ' (' . scalar @{$self->order->phone_notes} . ')' : '')
+    ->flash('info', $is_new ? t8('Phone note has been created.') : t8('Phone note has been updated.'))
+    ->render;
+}
+
+sub action_delete_phone_note {
+  my ($self) = @_;
+
+  my $phone_note = first { $_->id == $::form->{phone_note}->{id} } @{$self->order->phone_notes};
+
+  return $self->js->flash('error', t8('Phone note not found for this order.'))->render if !$phone_note;
+
+  $phone_note->delete;
+  $self->order(SL::DB::Order->new(id => $self->order->id)->load);
+
+  my $tab_as_html = $self->p->render('order/tabs/phone_notes', SELF => $self);
+
+  return $self->js
+    ->replaceWith('#phone-notes', $tab_as_html)
+    ->html('#num_phone_notes', (scalar @{$self->order->phone_notes}) ? ' (' . scalar @{$self->order->phone_notes} . ')' : '')
+    ->flash('info', t8('Phone note has been deleted.'))
+    ->render;
+}
+
 sub js_load_second_row {
   my ($self, $item, $item_id, $do_parse) = @_;
 
@@ -1284,6 +1494,17 @@ sub init_part_picker_classification_ids {
 sub check_auth {
   my ($self) = @_;
 
+  my $right_for = { map { $_ => $_.'_edit' . ' | ' . $_.'_view' } @{$self->valid_types} };
+
+  my $right   = $right_for->{ $self->type };
+  $right    ||= 'DOES_NOT_EXIST';
+
+  $::auth->assert($right);
+}
+
+sub check_auth_for_edit {
+  my ($self) = @_;
+
   my $right_for = { map { $_ => $_.'_edit' } @{$self->valid_types} };
 
   my $right   = $right_for->{ $self->type };
@@ -1307,6 +1528,24 @@ sub build_contact_select {
   );
 }
 
+# build the selection box for the additional billing address
+#
+# Needed, if customer/vendor changed.
+sub build_billing_address_select {
+  my ($self) = @_;
+
+  return '' if $self->cv ne 'customer';
+
+  select_tag('order.billing_address_id',
+             [ {displayable_id => '', id => ''}, $self->order->{$self->cv}->additional_billing_addresses ],
+             value_key  => 'id',
+             title_key  => 'displayable_id',
+             default    => $self->order->billing_address_id,
+             with_empty => 0,
+             style      => 'width: 300px',
+  );
+}
+
 # build the selection box for shiptos
 #
 # Needed, if customer/vendor changed.
@@ -1499,58 +1738,29 @@ sub new_item {
   }
 
   $item->assign_attributes(%$attr);
+  $item->qty(1.0)                   if !$item->qty;
+  $item->unit($item->part->unit)    if !$item->unit;
 
-  my $part         = SL::DB::Part->new(id => $attr->{parts_id})->load;
-  my $price_source = SL::PriceSource->new(record_item => $item, record => $record);
-
-  $item->unit($part->unit) if !$item->unit;
-
-  my $price_src;
-  if ( $part->is_assortment ) {
-    # add assortment items with price 0, as the components carry the price
-    $price_src = $price_source->price_from_source("");
-    $price_src->price(0);
-  } elsif (defined $item->sellprice) {
-    $price_src = $price_source->price_from_source("");
-    $price_src->price($item->sellprice);
-  } else {
-    $price_src = $price_source->best_price
-               ? $price_source->best_price
-               : $price_source->price_from_source("");
-    $price_src->price($::form->round_amount($price_src->price / $record->exchangerate, 5)) if $record->exchangerate;
-    $price_src->price(0) if !$price_source->best_price;
-  }
-
-  my $discount_src;
-  if (defined $item->discount) {
-    $discount_src = $price_source->discount_from_source("");
-    $discount_src->discount($item->discount);
-  } else {
-    $discount_src = $price_source->best_discount
-                  ? $price_source->best_discount
-                  : $price_source->discount_from_source("");
-    $discount_src->discount(0) if !$price_source->best_discount;
-  }
+  my ($price_src, $discount_src) = get_best_price_and_discount_source($record, $item, 0);
 
   my %new_attr;
-  $new_attr{part}                   = $part;
-  $new_attr{description}            = $part->description     if ! $item->description;
-  $new_attr{qty}                    = 1.0                    if ! $item->qty;
-  $new_attr{price_factor_id}        = $part->price_factor_id if ! $item->price_factor_id;
+  $new_attr{description}            = $item->part->description     if ! $item->description;
+  $new_attr{qty}                    = 1.0                          if ! $item->qty;
+  $new_attr{price_factor_id}        = $item->part->price_factor_id if ! $item->price_factor_id;
   $new_attr{sellprice}              = $price_src->price;
   $new_attr{discount}               = $discount_src->discount;
   $new_attr{active_price_source}    = $price_src;
   $new_attr{active_discount_source} = $discount_src;
-  $new_attr{longdescription}        = $part->notes           if ! defined $attr->{longdescription};
+  $new_attr{longdescription}        = $item->part->notes           if ! defined $attr->{longdescription};
   $new_attr{project_id}             = $record->globalproject_id;
-  $new_attr{lastcost}               = $record->is_sales ? $part->lastcost : 0;
+  $new_attr{lastcost}               = $record->is_sales ? $item->part->lastcost : 0;
 
   # add_custom_variables adds cvars to an orderitem with no cvars for saving, but
   # they cannot be retrieved via custom_variables until the order/orderitem is
   # saved. Adding empty custom_variables to new orderitem here solves this problem.
   $new_attr{custom_variables} = [];
 
-  my $texts = get_part_texts($part, $record->language_id, description => $new_attr{description}, longdescription => $new_attr{longdescription});
+  my $texts = get_part_texts($item->part, $record->language_id, description => $new_attr{description}, longdescription => $new_attr{longdescription});
 
   $item->assign_attributes(%new_attr, %{ $texts });
 
@@ -1560,17 +1770,19 @@ sub new_item {
 sub setup_order_from_cv {
   my ($order) = @_;
 
-  $order->$_($order->customervendor->$_) for (qw(taxzone_id payment_id delivery_term_id currency_id));
+  $order->$_($order->customervendor->$_) for (qw(taxzone_id payment_id delivery_term_id currency_id language_id));
 
   $order->intnotes($order->customervendor->notes);
 
-  if ($order->is_sales) {
-    $order->salesman_id($order->customer->salesman_id || SL::DB::Manager::Employee->current->id);
-    $order->taxincluded(defined($order->customer->taxincluded_checked)
-                        ? $order->customer->taxincluded_checked
-                        : $::myconfig{taxincluded_checked});
-  }
+  return if !$order->is_sales;
+
+  $order->salesman_id($order->customer->salesman_id || SL::DB::Manager::Employee->current->id);
+  $order->taxincluded(defined($order->customer->taxincluded_checked)
+                      ? $order->customer->taxincluded_checked
+                      : $::myconfig{taxincluded_checked});
 
+  my $address = $order->customer->default_billing_address;;
+  $order->billing_address_id($address ? $address->id : undef);
 }
 
 # setup custom shipto from form
@@ -1665,6 +1877,29 @@ sub save {
   my $errors = [];
   my $db     = $self->order->db;
 
+  # check for new or updated phone note
+  if ($::form->{phone_note}->{subject} || $::form->{phone_note}->{body}) {
+    if (!$::form->{phone_note}->{subject} || !$::form->{phone_note}->{body}) {
+      return [t8('Phone note needs a subject and a body.')];
+    }
+
+    my $phone_note;
+    if ($::form->{phone_note}->{id}) {
+      $phone_note = first { $_->id == $::form->{phone_note}->{id} } @{$self->order->phone_notes};
+      return [t8('Phone note not found for this order.')] if !$phone_note;
+    }
+
+    $phone_note = SL::DB::Note->new() if !$phone_note;
+    my $is_new  = !$phone_note->id;
+
+    $phone_note->assign_attributes(%{ $::form->{phone_note} },
+                                   trans_id     => $self->order->id,
+                                   trans_module => 'oe',
+                                   employee     => SL::DB::Manager::Employee->current);
+
+    $self->order->add_phone_notes($phone_note) if $is_new;
+  }
+
   $db->with_transaction(sub {
     # delete custom shipto if it is to be deleted or if it is empty
     if ($self->order->custom_shipto && ($self->is_custom_shipto_to_delete || $self->order->custom_shipto->is_empty)) {
@@ -1678,6 +1913,7 @@ sub save {
     # link records
     if ($::form->{converted_from_oe_id}) {
       my @converted_from_oe_ids = split ' ', $::form->{converted_from_oe_id};
+
       foreach my $converted_from_oe_id (@converted_from_oe_ids) {
         my $src = SL::DB::Order->new(id => $converted_from_oe_id)->load;
         $src->update_attributes(closed => 1) if $src->type =~ /_quotation$/;
@@ -1696,8 +1932,12 @@ sub save {
           $idx++;
         }
       }
+
+      $self->link_requirement_specs_linking_to_created_from_objects(@converted_from_oe_ids);
     }
 
+    $self->set_project_in_linked_requirement_specs if $self->order->globalproject_id;
+
     $self->save_history('SAVED');
 
     1;
@@ -1720,7 +1960,10 @@ sub workflow_sales_or_request_for_quotation {
   my $destination_type = $::form->{type} eq sales_order_type() ? sales_quotation_type() : request_quotation_type();
 
   $self->order(SL::DB::Order->new_from($self->order, destination_type => $destination_type));
-  $self->{converted_from_oe_id} = delete $::form->{id};
+  delete $::form->{id};
+
+  # no linked records from order to quotations
+  delete $::form->{$_} for qw(converted_from_oe_id converted_from_orderitems_ids);
 
   # set item ids to new fake id, to identify them as new items
   foreach my $item (@{$self->order->items_sorted}) {
@@ -1820,7 +2063,7 @@ sub pre_render {
   $self->{all_taxzones}               = SL::DB::Manager::TaxZone->get_all_sorted();
   $self->{all_currencies}             = SL::DB::Manager::Currency->get_all_sorted();
   $self->{all_departments}            = SL::DB::Manager::Department->get_all_sorted();
-  $self->{all_languages}              = SL::DB::Manager::Language->get_all_sorted();
+  $self->{all_languages}              = SL::DB::Manager::Language->get_all_sorted( query => [ or => [ obsolete => 0, id => $self->order->language_id ] ] );
   $self->{all_employees}              = SL::DB::Manager::Employee->get_all(where => [ or => [ id => $self->order->employee_id,
                                                                                               deleted => 0 ] ],
                                                                            sort_by => 'name');
@@ -1845,7 +2088,7 @@ sub pre_render {
                 no_queue           => 1,
                 no_postscript      => 1,
                 no_opendocument    => 0,
-                no_html            => 1},
+                no_html            => 0},
   );
 
   foreach my $item (@{$self->order->orderitems}) {
@@ -1873,10 +2116,18 @@ sub pre_render {
                                                 } } @all_objects;
   }
 
+  if (   (any { $self->type eq $_ } (sales_quotation_type(), sales_order_type()))
+      && $::instance_conf->get_transport_cost_reminder_article_number_id ) {
+    $self->{template_args}->{transport_cost_reminder_article} = SL::DB::Part->new(id => $::instance_conf->get_transport_cost_reminder_article_number_id)->load;
+  }
+  $self->{template_args}->{longdescription_dialog_size_percentage} = SL::Helper::UserPreferences::DisplayPreferences->new()->get_longdescription_dialog_size_percentage();
+
   $self->get_item_cvpartnumber($_) for @{$self->order->items_sorted};
 
-  $::request->{layout}->use_javascript("${_}.js") for qw(kivi.SalesPurchase kivi.Order kivi.File ckeditor/ckeditor ckeditor/adapters/jquery
-                                                         edit_periodic_invoices_config calculate_qty kivi.Validator follow_up show_history);
+  $self->{template_args}->{num_phone_notes} = scalar @{ $self->order->phone_notes || [] };
+
+  $::request->{layout}->use_javascript("${_}.js") for qw(kivi.Validator kivi.SalesPurchase kivi.Order kivi.File ckeditor/ckeditor ckeditor/adapters/jquery
+                                                         edit_periodic_invoices_config calculate_qty follow_up show_history);
   $self->setup_edit_action_bar;
 }
 
@@ -1887,6 +2138,26 @@ sub setup_edit_action_bar {
                       || (($self->type eq sales_order_type())    && $::instance_conf->get_sales_order_show_delete)
                       || (($self->type eq purchase_order_type()) && $::instance_conf->get_purchase_order_show_delete);
 
+  my @req_trans_cost_art = qw(kivi.Order.check_transport_cost_article_presence) x!!$::instance_conf->get_transport_cost_reminder_article_number_id;
+  my @req_cusordnumber   = qw(kivi.Order.check_cusordnumber_presence)           x($self->type eq sales_order_type() && $::instance_conf->get_order_warn_no_cusordnumber);
+
+  my $has_invoice_for_advance_payment;
+  if ($self->order->id && $self->type eq sales_order_type()) {
+    my $lr = $self->order->linked_records(direction => 'to', to => ['Invoice']);
+    $has_invoice_for_advance_payment = any {'SL::DB::Invoice' eq ref $_ && "invoice_for_advance_payment" eq $_->type} @$lr;
+  }
+
+  my $has_final_invoice;
+  if ($self->order->id && $self->type eq sales_order_type()) {
+    my $lr = $self->order->linked_records(direction => 'to', to => ['Invoice']);
+    $has_final_invoice               = any {'SL::DB::Invoice' eq ref $_ && "final_invoice" eq $_->type} @$lr;
+  }
+
+  my $right_for         = { map { $_ => $_.'_edit' } @{$self->valid_types} };
+  my $right             = $right_for->{ $self->type };
+  $right              ||= 'DOES_NOT_EXIST';
+  my $may_edit_create   = $::auth->assert($right, 'may fail');
+
   for my $bar ($::request->layout->get('actionbar')) {
     $bar->add(
       combobox => [
@@ -1894,14 +2165,32 @@ sub setup_edit_action_bar {
           t8('Save'),
           call      => [ 'kivi.Order.save', 'save', $::instance_conf->get_order_warn_duplicate_parts,
                                                     $::instance_conf->get_order_warn_no_deliverydate,
-                                                                                                      ],
-          checks    => [ 'kivi.Order.check_save_active_periodic_invoices', ['kivi.validate_form','#order_form'] ],
+          ],
+          checks    => [ 'kivi.Order.check_save_active_periodic_invoices', ['kivi.validate_form','#order_form'],
+                         @req_trans_cost_art, @req_cusordnumber,
+          ],
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and Close'),
+          call      => [ 'kivi.Order.save', 'save', $::instance_conf->get_order_warn_duplicate_parts,
+                                                    $::instance_conf->get_order_warn_no_deliverydate,
+                                                    1
+          ],
+          checks    => [ 'kivi.Order.check_save_active_periodic_invoices', ['kivi.validate_form','#order_form'],
+                         @req_trans_cost_art, @req_cusordnumber,
+          ],
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
         ],
         action => [
           t8('Save as new'),
           call      => [ 'kivi.Order.save', 'save_as_new', $::instance_conf->get_order_warn_duplicate_parts ],
-          checks    => [ 'kivi.Order.check_save_active_periodic_invoices' ],
-          disabled  => !$self->order->id ? t8('This object has not been saved yet.') : undef,
+          checks    => [ 'kivi.Order.check_save_active_periodic_invoices',
+                         @req_trans_cost_art, @req_cusordnumber,
+          ],
+          disabled  => !$may_edit_create ? t8('You do not have the permissions to access this function.')
+                     : !$self->order->id ? t8('This object has not been saved yet.')
+                     :                     undef,
         ],
       ], # end of combobox "Save"
 
@@ -1912,40 +2201,87 @@ sub setup_edit_action_bar {
         action => [
           t8('Save and Quotation'),
           submit   => [ '#order_form', { action => "Order/sales_quotation" } ],
+          checks   => [ @req_trans_cost_art, @req_cusordnumber ],
           only_if  => (any { $self->type eq $_ } (sales_order_type())),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
         ],
         action => [
           t8('Save and RFQ'),
           submit   => [ '#order_form', { action => "Order/request_for_quotation" } ],
           only_if  => (any { $self->type eq $_ } (purchase_order_type())),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
         ],
         action => [
           t8('Save and Sales Order'),
           submit   => [ '#order_form', { action => "Order/sales_order" } ],
+          checks   => [ @req_trans_cost_art ],
           only_if  => (any { $self->type eq $_ } (sales_quotation_type(), purchase_order_type())),
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
         ],
         action => [
           t8('Save and Purchase Order'),
           call      => [ 'kivi.Order.purchase_order_check_for_direct_delivery' ],
+          checks    => [ @req_trans_cost_art, @req_cusordnumber ],
           only_if   => (any { $self->type eq $_ } (sales_order_type(), request_quotation_type())),
+          disabled  => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
         ],
         action => [
           t8('Save and Delivery Order'),
           call      => [ 'kivi.Order.save', 'save_and_delivery_order', $::instance_conf->get_order_warn_duplicate_parts,
                                                                        $::instance_conf->get_order_warn_no_deliverydate,
                                                                                                                         ],
-          checks    => [ 'kivi.Order.check_save_active_periodic_invoices' ],
-          only_if   => (any { $self->type eq $_ } (sales_order_type(), purchase_order_type()))
+          checks    => [ 'kivi.Order.check_save_active_periodic_invoices',
+                         @req_trans_cost_art, @req_cusordnumber,
+          ],
+          only_if   => (any { $self->type eq $_ } (sales_order_type(), purchase_order_type())),
+          disabled  => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          t8('Save and Supplier Delivery Order'),
+          call      => [ 'kivi.Order.save', 'save_and_supplier_delivery_order', $::instance_conf->get_order_warn_duplicate_parts,
+                                                                       $::instance_conf->get_order_warn_no_deliverydate,
+                                                                                                                        ],
+          checks    => [ 'kivi.Order.check_save_active_periodic_invoices',
+                         @req_trans_cost_art, @req_cusordnumber,
+          ],
+          only_if   => (any { $self->type eq $_ } (purchase_order_type())),
+          disabled  => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
         ],
         action => [
           t8('Save and Invoice'),
           call      => [ 'kivi.Order.save', 'save_and_invoice', $::instance_conf->get_order_warn_duplicate_parts ],
-          checks    => [ 'kivi.Order.check_save_active_periodic_invoices' ],
+          checks    => [ 'kivi.Order.check_save_active_periodic_invoices',
+                         @req_trans_cost_art, @req_cusordnumber,
+          ],
+          disabled  => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
+        ],
+        action => [
+          ($has_invoice_for_advance_payment ? t8('Save and Further Invoice for Advance Payment') : t8('Save and Invoice for Advance Payment')),
+          call      => [ 'kivi.Order.save', 'save_and_invoice_for_advance_payment', $::instance_conf->get_order_warn_duplicate_parts ],
+          checks    => [ 'kivi.Order.check_save_active_periodic_invoices',
+                         @req_trans_cost_art, @req_cusordnumber,
+          ],
+          disabled  => !$may_edit_create  ? t8('You do not have the permissions to access this function.')
+                     : $has_final_invoice ? t8('This order has already a final invoice.')
+                     :                      undef,
+          only_if   => (any { $self->type eq $_ } (sales_order_type())),
+        ],
+        action => [
+          t8('Save and Final Invoice'),
+          call      => [ 'kivi.Order.save', 'save_and_final_invoice', $::instance_conf->get_order_warn_duplicate_parts ],
+          checks    => [ 'kivi.Order.check_save_active_periodic_invoices',
+                         @req_trans_cost_art, @req_cusordnumber,
+          ],
+          disabled  => !$may_edit_create  ? t8('You do not have the permissions to access this function.')
+                     : $has_final_invoice ? t8('This order has already a final invoice.')
+                     :                      undef,
+          only_if   => (any { $self->type eq $_ } (sales_order_type())) && $has_invoice_for_advance_payment,
         ],
         action => [
           t8('Save and AP Transaction'),
           call      => [ 'kivi.Order.save', 'save_and_ap_transaction', $::instance_conf->get_order_warn_duplicate_parts ],
-          only_if   => (any { $self->type eq $_ } (purchase_order_type()))
+          only_if   => (any { $self->type eq $_ } (purchase_order_type())),
+          disabled  => !$may_edit_create  ? t8('You do not have the permissions to access this function.') : undef,
         ],
 
       ], # end of combobox "Workflow"
@@ -1956,23 +2292,29 @@ sub setup_edit_action_bar {
         ],
         action => [
           t8('Save and preview PDF'),
-           call => [ 'kivi.Order.save', 'preview_pdf', $::instance_conf->get_order_warn_duplicate_parts,
-                                                       $::instance_conf->get_order_warn_no_deliverydate,
-                                                                                                         ],
+          call     => [ 'kivi.Order.save', 'preview_pdf', $::instance_conf->get_order_warn_duplicate_parts,
+                                                          $::instance_conf->get_order_warn_no_deliverydate,
+                      ],
+          checks   => [ @req_trans_cost_art, @req_cusordnumber ],
+          disabled => !$may_edit_create  ? t8('You do not have the permissions to access this function.') : undef,
         ],
         action => [
           t8('Save and print'),
-          call => [ 'kivi.Order.show_print_options', $::instance_conf->get_order_warn_duplicate_parts,
-                                                     $::instance_conf->get_order_warn_no_deliverydate,
-                                                                                                      ],
+          call     => [ 'kivi.Order.show_print_options', $::instance_conf->get_order_warn_duplicate_parts,
+                                                         $::instance_conf->get_order_warn_no_deliverydate,
+                      ],
+          checks   => [ @req_trans_cost_art, @req_cusordnumber ],
+          disabled => !$may_edit_create  ? t8('You do not have the permissions to access this function.') : undef,
         ],
         action => [
           t8('Save and E-mail'),
-          id   => 'save_and_email_action',
-          call => [ 'kivi.Order.save', 'save_and_show_email_dialog', $::instance_conf->get_order_warn_duplicate_parts,
-                                                                     $::instance_conf->get_order_warn_no_deliverydate,
-                  ],
-          disabled => !$self->order->id ? t8('This object has not been saved yet.') : undef,
+          id       => 'save_and_email_action',
+          call     => [ 'kivi.Order.save', 'save_and_show_email_dialog', $::instance_conf->get_order_warn_duplicate_parts,
+                                                                         $::instance_conf->get_order_warn_no_deliverydate,
+                      ],
+          disabled => !$may_edit_create  ? t8('You do not have the permissions to access this function.')
+                    : !$self->order->id  ? t8('This object has not been saved yet.')
+                    :                      undef,
         ],
         action => [
           t8('Download attachments of all parts'),
@@ -1986,7 +2328,9 @@ sub setup_edit_action_bar {
         t8('Delete'),
         call     => [ 'kivi.Order.delete_order' ],
         confirm  => $::locale->text('Do you really want to delete this object?'),
-        disabled => !$self->order->id ? t8('This object has not been saved yet.') : undef,
+        disabled => !$may_edit_create  ? t8('You do not have the permissions to access this function.')
+                  : !$self->order->id  ? t8('This object has not been saved yet.')
+                  :                      undef,
         only_if  => $deletion_allowed,
       ],
 
@@ -1994,25 +2338,26 @@ sub setup_edit_action_bar {
         action => [
           t8('more')
         ],
+        action => [
+          t8('History'),
+          call     => [ 'set_history_window', $self->order->id, 'id' ],
+          disabled => !$self->order->id ? t8('This record has not been saved yet.') : undef,
+        ],
         action => [
           t8('Follow-Up'),
           call     => [ 'kivi.Order.follow_up_window' ],
           disabled => !$self->order->id ? t8('This object has not been saved yet.') : undef,
           only_if  => $::auth->assert('productivity', 1),
         ],
-        action => [
-          t8('History'),
-          call     => [ 'set_history_window', $self->order->id, 'id' ],
-          disabled => !$self->order->id ? t8('This record has not been saved yet.') : undef,
-        ],
       ], # end of combobox "more"
     );
   }
 }
 
-sub generate_pdf {
-  my ($order, $pdf_ref, $params) = @_;
+sub generate_doc {
+  my ($self, $doc_ref, $params) = @_;
 
+  my $order  = $self->order;
   my @errors = ();
 
   my $print_form = Form->new('');
@@ -2032,6 +2377,9 @@ sub generate_pdf {
   if ($print_form->{format} =~ /(opendocument|oasis)/i) {
     $template_ext  = 'odt';
     $template_type = 'OpenDocument';
+  } elsif ($print_form->{format} =~ m{html}i) {
+    $template_ext  = 'html';
+    $template_type = 'HTML';
   }
 
   # search for the template
@@ -2053,7 +2401,7 @@ sub generate_pdf {
     eval {
       $print_form->prepare_for_printing;
 
-      $$pdf_ref = SL::Helper::CreatePDF->create_pdf(
+      $$doc_ref = SL::Helper::CreatePDF->create_pdf(
         format        => $print_form->{format},
         template_type => $template_type,
         template      => $template_file,
@@ -2062,6 +2410,7 @@ sub generate_pdf {
           longdescription => 'html',
           partnotes       => 'html',
           notes           => 'html',
+          $::form->get_variable_content_types_for_cvars,
         },
       );
       1;
@@ -2189,6 +2538,41 @@ sub get_part_texts {
   return $texts;
 }
 
+sub get_best_price_and_discount_source {
+  my ($record, $item, $ignore_given) = @_;
+
+  my $price_source = SL::PriceSource->new(record_item => $item, record => $record);
+
+  my $price_src;
+  if ( $item->part->is_assortment ) {
+    # add assortment items with price 0, as the components carry the price
+    $price_src = $price_source->price_from_source("");
+    $price_src->price(0);
+  } elsif (!$ignore_given && defined $item->sellprice) {
+    $price_src = $price_source->price_from_source("");
+    $price_src->price($item->sellprice);
+  } else {
+    $price_src = $price_source->best_price
+               ? $price_source->best_price
+               : $price_source->price_from_source("");
+    $price_src->price($::form->round_amount($price_src->price / $record->exchangerate, 5)) if $record->exchangerate;
+    $price_src->price(0) if !$price_source->best_price;
+  }
+
+  my $discount_src;
+  if (!$ignore_given && defined $item->discount) {
+    $discount_src = $price_source->discount_from_source("");
+    $discount_src->discount($item->discount);
+  } else {
+    $discount_src = $price_source->best_discount
+                  ? $price_source->best_discount
+                  : $price_source->discount_from_source("");
+    $discount_src->discount(0) if !$price_source->best_discount;
+  }
+
+  return ($price_src, $discount_src);
+}
+
 sub sales_order_type {
   'sales_order';
 }
@@ -2248,9 +2632,10 @@ sub save_history {
   )->save;
 }
 
-sub store_pdf_to_webdav_and_filemanagement {
-  my($order, $content, $filename) = @_;
+sub store_doc_to_webdav_and_filemanagement {
+  my ($self, $content, $filename, $variant) = @_;
 
+  my $order = $self->order;
   my @errors;
 
   # copy file to webdav folder
@@ -2267,27 +2652,54 @@ sub store_pdf_to_webdav_and_filemanagement {
       $webdav_file->store(data => \$content);
       1;
     } or do {
-      push @errors, t8('Storing PDF to webdav folder failed: #1', $@);
+      push @errors, t8('Storing the document to the WebDAV folder failed: #1', $@);
     };
   }
   if ($order->id && $::instance_conf->get_doc_storage) {
     eval {
       SL::File->save(object_id     => $order->id,
                      object_type   => $order->type,
-                     mime_type     => 'application/pdf',
+                     mime_type     => SL::MIME->mime_type_from_ext($filename),
                      source        => 'created',
                      file_type     => 'document',
                      file_name     => $filename,
-                     file_contents => $content);
+                     file_contents => $content,
+                     print_variant => $variant);
       1;
     } or do {
-      push @errors, t8('Storing PDF in storage backend failed: #1', $@);
+      push @errors, t8('Storing the document in the storage backend failed: #1', $@);
     };
   }
 
   return @errors;
 }
 
+sub link_requirement_specs_linking_to_created_from_objects {
+  my ($self, @converted_from_oe_ids) = @_;
+
+  return unless @converted_from_oe_ids;
+
+  my $rs_orders = SL::DB::Manager::RequirementSpecOrder->get_all(where => [ order_id => \@converted_from_oe_ids ]);
+  foreach my $rs_order (@{ $rs_orders }) {
+    SL::DB::RequirementSpecOrder->new(
+      order_id            => $self->order->id,
+      requirement_spec_id => $rs_order->requirement_spec_id,
+      version_id          => $rs_order->version_id,
+    )->save;
+  }
+}
+
+sub set_project_in_linked_requirement_specs {
+  my ($self) = @_;
+
+  my $rs_orders = SL::DB::Manager::RequirementSpecOrder->get_all(where => [ order_id => $self->order->id ]);
+  foreach my $rs_order (@{ $rs_orders }) {
+    next if $rs_order->requirement_spec->project_id == $self->order->globalproject_id;
+
+    $rs_order->requirement_spec->update_attributes(project_id => $self->order->globalproject_id);
+  }
+}
+
 1;
 
 __END__
@@ -2416,7 +2828,7 @@ java script functions
 =item * optional client/user behaviour
 
 (transactions has to be set - department has to be set -
- force project if enabled in client config - transport cost reminder)
+ force project if enabled in client config)
 
 =back
 
@@ -2426,21 +2838,10 @@ java script functions
 
 =item *
 
-Customer discount is not displayed as a valid discount in price source popup
-(this might be a bug in price sources)
-
-(I cannot reproduce this (Bernd))
-
-=item *
-
 No indication that <shift>-up/down expands/collapses second row.
 
 =item *
 
-Inline creation of parts is not currently supported
-
-=item *
-
 Table header is not sticky in the scrolling area.
 
 =item *
@@ -2463,10 +2864,6 @@ How to expand/collapse second row. Now it can be done clicking the icon or
 
 =item *
 
-Possibility to select PriceSources in input row?
-
-=item *
-
 This controller uses a (changed) copy of the template for the PriceSource
 dialog. Maybe there could be used one code source.
 
index cdab2a4..aae4e53 100644 (file)
@@ -160,6 +160,26 @@ sub action_save {
   }
 }
 
+sub action_save_and_purchase_order {
+  my ($self) = @_;
+
+  my $session_value;
+  if (1 == scalar @{$self->part->makemodels}) {
+    my $prepared_form           = Form->new('');
+    $prepared_form->{vendor_id} = $self->part->makemodels->[0]->make;
+    $session_value              = $::auth->save_form_in_session(form => $prepared_form);
+  }
+
+  $::form->{callback} = $self->url_for(
+    controller   => 'Order',
+    action       => 'return_from_create_part',
+    type         => 'purchase_order',
+    previousform => $session_value,
+  );
+
+  $self->_run_action('save');
+}
+
 sub action_abort {
   my ($self) = @_;
 
@@ -709,7 +729,7 @@ sub add {
 
 sub _set_javascript {
   my ($self) = @_;
-  $::request->layout->use_javascript("${_}.js")  for qw(kivi.Part kivi.File kivi.PriceRule ckeditor/ckeditor ckeditor/adapters/jquery kivi.ShopPart);
+  $::request->layout->use_javascript("${_}.js")  for qw(kivi.Part kivi.File kivi.PriceRule ckeditor/ckeditor ckeditor/adapters/jquery kivi.ShopPart kivi.Validator);
   $::request->layout->add_javascripts_inline("\$(function(){kivi.PriceRule.load_price_rules_for_part(@{[ $self->part->id ]})});") if $self->part->id;
 }
 
@@ -1100,7 +1120,7 @@ sub init_all_price_factors {
 }
 
 sub init_all_pricegroups {
-  SL::DB::Manager::Pricegroup->get_all_sorted;
+  SL::DB::Manager::Pricegroup->get_all_sorted(query => [ obsolete => 0 ]);
 }
 
 # model used to filter/display the parts in the multi-items dialog
@@ -1335,6 +1355,7 @@ sub _setup_form_action_bar {
           t8('Save'),
           call      => [ 'kivi.Part.save' ],
           disabled  => !$may_edit ? t8('You do not have the permissions to access this function.') : undef,
+          checks    => ['kivi.validate_form'],
         ],
         action => [
           t8('Use as new'),
@@ -1345,10 +1366,24 @@ sub _setup_form_action_bar {
         ],
       ], # end of combobox "Save"
 
+      combobox => [
+        action => [ t8('Workflow') ],
+        action => [
+          t8('Save and Purchase Order'),
+          submit   => [ '#ic', { action => "Part/save_and_purchase_order" } ],
+          checks   => ['kivi.validate_form'],
+          disabled => !$self->part->id                                    ? t8('The object has not been saved yet.')
+                    : !$may_edit                                          ? t8('You do not have the permissions to access this function.')
+                    : !$::auth->assert('purchase_order_edit', 'may fail') ? t8('You do not have the permissions to access this function.')
+                    :                                                       undef,
+          only_if  => !$::form->{inline_create},
+        ],
+      ],
+
       action => [
         t8('Abort'),
         submit   => [ '#ic', { action => "Part/abort" } ],
-        only_if  => !!$::form->{show_abort},
+        only_if  => !!$::form->{inline_create},
       ],
 
       action => [
index 03a44d0..c8d3909 100644 (file)
@@ -28,7 +28,7 @@ sub action_import_datev_pay_postings {
   my $filename= $::form->{ATTACHMENTS}{file}{filename};
   # check name and first fields of CSV data
   die t8("Wrong file name, expects name like: DTVF_*_LOHNBUCHUNG*.csv") unless $filename =~ /^DTVF_.*_LOHNBUCHUNGEN_LUG.*\.csv$/;
-  die t8("not a valid DTVF file, expected first field in A1 'DTVF'")   unless ($::form->{file} =~ m/^"DTVF";/);
+  die t8("not a valid DTVF file, expected first field in A1 'DTVF'")    unless ($::form->{file} =~ m/^('|")?DTVF/);
   die t8("not a valid DTVF file, expected field header start with 'Umsatz; (..) ;Konto;Gegenkonto'")
     unless ($::form->{file} =~ m/Umsatz;S\/H;;;;;Konto;Gegenkonto.*;;Belegdatum;Belegfeld 1;Belegfeld 2;;Buchungstext/);
 
@@ -81,7 +81,9 @@ sub parse_and_import {
 
       # optional KOST1 - KOST2 ?
       $department_name = $row->[36];
-      $department    = SL::DB::Manager::Department->get_first(description => { like =>  $department_name . '%' });
+      if ($department_name) {
+        $department    = SL::DB::Manager::Department->get_first(where => [ description => { ilike =>  $department_name . '%' } ]);
+      }
 
       my $amount = $::form->parse_amount({ numberformat => '1000,00' }, $row->[0]);
 
index 85e3765..c0c113c 100644 (file)
@@ -83,6 +83,8 @@ sub _make_record_item {
     sales_quotation         => 'OrderItem',
     request_quotation       => 'OrderItem',
     invoice                 => 'InvoiceItem',
+    invoice_for_advance_payment => 'InvoiceItem',
+    final_invoice           => 'InvoiceItem',
     purchase_invoice        => 'InvoiceItem',
     credit_note             => 'InvoiceItem',
     purchase_delivery_order => 'DeliveryOrderItem',
index 94862e1..702db89 100644 (file)
@@ -248,7 +248,7 @@ sub display_form {
 
   CVar->render_inputs(variables => $params{CUSTOM_VARIABLES}) if @{ $params{CUSTOM_VARIABLES} };
 
-  $::request->layout->use_javascript('kivi.File.js');
+  $::request->layout->use_javascript("$_.js") for qw(kivi.File ckeditor/ckeditor ckeditor/adapters/jquery);
   $self->setup_edit_action_bar(callback => $params{callback});
 
   $self->render('project/form', %params);
index eec3ce2..49661cb 100644 (file)
@@ -43,16 +43,19 @@ my @link_type_specifics = (
   { title => t8('Sales quotation'),         type => 'sales_quotation',         model => 'Order',           number => 'quonumber', },
   { title => t8('Sales Order'),             type => 'sales_order',             model => 'Order',           number => 'ordnumber', },
   { title => t8('Sales delivery order'),    type => 'sales_delivery_order',    model => 'DeliveryOrder',   number => 'donumber',  },
+  { title => t8('RMA delivery order'),      type => 'rma_delivery_order',      model => 'DeliveryOrder',   number => 'rdonumber', },
   { title => t8('Sales Invoice'),           type => 'invoice',                 model => 'Invoice',         number => 'invnumber', },
   { title => t8('Request for Quotation'),   type => 'request_quotation',       model => 'Order',           number => 'quonumber', },
   { title => t8('Purchase Order'),          type => 'purchase_order',          model => 'Order',           number => 'ordnumber', },
   { title => t8('Purchase delivery order'), type => 'purchase_delivery_order', model => 'DeliveryOrder',   number => 'donumber',  },
+  { title => t8('Supplier delivery order'), type => 'supplier_delivery_order', model => 'DeliveryOrder',   number => 'sdonumber', },
   { title => t8('Purchase Invoice'),        type => 'purchase_invoice',        model => 'PurchaseInvoice', number => 'invnumber', },
   { title => t8('Letter'),                  type => 'letter',                  model => 'Letter',          number => 'letternumber', description => 'subject', description_title => t8('Subject'), date => 'date', project => undef },
   { title => t8('Email'),                   type => 'email_journal',           model => 'EmailJournal',    number => 'id', description => 'subject', description_title => t8('Subject'), },
   { title => t8('AR Transaction'),          type => 'ar_transaction',          model => 'Invoice',         number => 'invnumber', },
   { title => t8('AP Transaction'),          type => 'ap_transaction',          model => 'PurchaseInvoice', number => 'invnumber', },
   { title => t8('Dunning'),                 type => 'dunning',                 model => 'Dunning',         number => 'dunning_id', },
+  { title => t8('GL Transaction'),          type => 'gl_transaction',          model => 'GLTransaction',   number => 'reference', },
 );
 
 my @link_types = map { +{ %link_type_defaults, %{ $_ } } } @link_type_specifics;
@@ -65,7 +68,10 @@ sub action_ajax_list {
   my ($self) = @_;
 
   eval {
-    my $linked_records = $self->object->linked_records(direction => 'both', recursive => 1, save_path => 1);
+    my $linked_records = ($::instance_conf->get_always_record_links_from_order && ref $self->object ne 'SL::DB::Order')
+                       ?  $self->get_order_centric_linked_records
+                       :  $self->object->linked_records(direction => 'both', recursive => 1, save_path => 1);
+
     push @{ $linked_records }, $self->object->sepa_export_items if $self->object->can('sepa_export_items');
 
     my $output         = grouped_record_list(
@@ -132,6 +138,7 @@ sub action_ajax_add_list {
   my $project_id  = "${project}_id";
   my $description = $self->link_type_desc->{description};
   my $filter      = $self->link_type_desc->{filter};
+  my $number      = $self->link_type_desc->{number};
 
   my @where = $filter && $manager->can($filter) ? $manager->$filter($self->link_type) : ();
   push @where, ("${vc}.${vc}number"     => { ilike => like($::form->{vc_number}) })               if $::form->{vc_number};
@@ -139,6 +146,16 @@ sub action_ajax_add_list {
   push @where, ($description            => { ilike => like($::form->{transaction_description}) }) if $::form->{transaction_description};
   push @where, ($project_id             => $::form->{globalproject_id})                           if $::form->{globalproject_id} && $manager->can($project_id);
 
+  if ($::form->{number}) {
+    my $class    = 'SL::DB::' . $self->link_type_desc->{model};
+    my $col_type = ref $class->meta->column($number);
+    if ($col_type =~ /^Rose::DB::Object::Metadata::Column::(?:Integer|Serial)$/) {
+      push @where, ($number => $::form->{number});
+    } elsif ($col_type =~ /^Rose::DB::Object::Metadata::Column::Text$/) {
+      push @where, ($number => { ilike => like($::form->{number}) });
+    }
+  }
+
   my @with_objects = ($vc);
   push @with_objects, $project if $manager->can($project_id);
 
@@ -231,4 +248,24 @@ sub check_auth {
   $::auth->assert('record_links');
 }
 
+# internal
+
+sub get_order_centric_linked_records {
+  my ($self) = @_;
+
+  my $all_linked_records = $self->object->linked_records(direction => 'from', recursive => 1);
+  my $filtered_orders = [ grep { 'SL::DB::Order' eq ref $_ && $_->is_type('sales_order') } @$all_linked_records ];
+
+  # no orders no call to linked_records via batch mode
+  # but instead return default list
+  return $self->object->linked_records(direction => 'both', recursive => 1, save_path => 1)
+    unless scalar @$filtered_orders;
+
+  # we have a order, therefore get the tree view from the top (order)
+  my $id_ref = [ map { $_->id } @$filtered_orders ];
+  my $linked_records = SL::DB::Order->new->linked_records(direction => 'to', recursive => 1, batch => $id_ref);
+  push @{ $linked_records }, @$filtered_orders;
+
+  return $linked_records;
+}
 1;
index 6ba1c4e..afbe2bb 100644 (file)
@@ -87,6 +87,7 @@ sub action_ajax_edit {
   $self->js
     ->hide('#basic_settings')
     ->after('#basic_settings', $html)
+    ->reinit_widgets
     ->render;
 }
 
@@ -333,7 +334,8 @@ sub setup {
 
   $::auth->assert('requirement_spec_edit');
   $::request->{layout}->use_stylesheet("${_}.css") for qw(jquery.contextMenu requirement_spec);
-  $::request->{layout}->use_javascript("${_}.js")  for qw(jquery.jstree jquery/jquery.contextMenu jquery/jquery.hotkeys requirement_spec ckeditor/ckeditor ckeditor/adapters/jquery kivi.Part kivi.CustomerVendor);
+  $::request->{layout}->use_javascript("${_}.js")  for qw(jquery.jstree jquery/jquery.contextMenu jquery/jquery.hotkeys requirement_spec ckeditor/ckeditor ckeditor/adapters/jquery kivi.Part kivi.CustomerVendor
+                                                          ckeditor/ckeditor ckeditor/adapters/jquery);
   $self->init_visible_section;
 
   return 1;
index 2da4a41..3e61c63 100644 (file)
@@ -63,7 +63,7 @@ sub action_get_orders {
     if($shop_fetched->{error}){
       flash_later('error', t8('From shop "#1" :  #2 ', $shop_fetched->{shop_description}, $shop_fetched->{message},));
     }else{
-      flash_later('info', t8('From shop #1 :  #2 shoporders have been fetched.', $shop_fetched->{description}, $shop_fetched->{number_of_orders},));
+      flash_later('info', t8('From shop #1 :  #2 shoporders have been fetched.', $shop_fetched->{shop_description}, $shop_fetched->{number_of_orders},));
     }
   }
 
index fb2fe92..6ab6507 100644 (file)
@@ -266,7 +266,6 @@ sub action_mass_upload {
 
 sub action_update {
   my ($self) = @_;
-
   $self->create_or_update;
 }
 
@@ -288,17 +287,15 @@ sub create_or_update {
   my ($self) = @_;
 
   my $is_new = !$self->shop_part->id;
-
   my $params = delete($::form->{shop_part}) || { };
-
   $self->shop_part->assign_attributes(%{ $params });
-
   $self->shop_part->save;
 
   my ( $price, $price_src_str ) = $self->get_price_n_pricesource($self->shop_part->active_price_source);
-if(!$is_new){
-  flash('info', $is_new ? t8('The shop part has been created.') : t8('The shop part has been saved.'));
-  $self->js->html('#shop_part_description_' . $self->shop_part->id, $self->shop_part->shop_description)
+
+  if(!$is_new){
+    flash('info', $is_new ? t8('The shop part has been created.') : t8('The shop part has been saved.'));
+    $self->js->html('#shop_part_description_' . $self->shop_part->id, $self->shop_part->shop_description)
            ->html('#shop_part_active_' . $self->shop_part->id, $self->shop_part->active)
            ->html('#price_' . $self->shop_part->id, $::form->format_amount(\%::myconfig,$price,2))
            ->html('#active_price_source_' . $self->shop_part->id, $price_src_str)
index 463d74f..f23edbf 100644 (file)
@@ -34,8 +34,10 @@ my %supported_types = (
       { method => 'iban',                                      title => t8('IBAN'), },
       { method => 'bank',                                      title => t8('Bank'), },
       { method => 'bank_code',                                 title => t8('Bank code'), },
+      { method => 'bank_account_id',                           title => t8('Bank Account Id Number (Swiss)'), },
       { method => 'bic',                                       title => t8('BIC'), },
       {                                                        title => t8('Use for Factur-X/ZUGFeRD'), formatter => sub { $_[0]->use_for_zugferd ? t8('yes') : t8('no') } },
+      {                                                        title => t8('Use for Swiss QR-Bill'), formatter => sub { $_[0]->use_for_qrbill ? t8('yes') : t8('no') } },
       { method => 'reconciliation_starting_date_as_date',      title => t8('Date'),    align => 'right' },
       { method => 'reconciliation_starting_balance_as_number', title => t8('Balance'), align => 'right' },
     ],
@@ -110,6 +112,7 @@ my %supported_types = (
       {                            title => t8('Number Format'), formatter => sub { $_[0]->output_numberformat || t8('use program settings') } },
       {                            title => t8('Date Format'),   formatter => sub { $_[0]->output_dateformat   || t8('use program settings') } },
       {                            title => t8('Long Dates'),    formatter => sub { $_[0]->output_longdates ? t8('yes') : t8('no') } },
+      {                            title => t8('Obsolete'),      formatter => sub { $_[0]->obsolete  ? t8('yes') : t8('no') } },
     ],
   },
 
index 03d6504..4d0aa94 100644 (file)
@@ -28,6 +28,7 @@ my @available_modules = (
   'SL::Controller::TopQuickSearch::GLTransaction',
   'SL::Controller::TopQuickSearch::Customer',
   'SL::Controller::TopQuickSearch::Vendor',
+  'SL::Controller::TopQuickSearch::PhoneNumber',
 );
 my %modules_by_name;
 
diff --git a/SL/Controller/TopQuickSearch/PhoneNumber.pm b/SL/Controller/TopQuickSearch/PhoneNumber.pm
new file mode 100644 (file)
index 0000000..54431e0
--- /dev/null
@@ -0,0 +1,85 @@
+package SL::Controller::TopQuickSearch::PhoneNumber;
+
+use strict;
+use parent qw(SL::Controller::TopQuickSearch::Base);
+
+use SL::Controller::TopQuickSearch::Customer;
+use SL::Controller::TopQuickSearch::Vendor;
+use SL::DB::Customer;
+use SL::DB::Vendor;
+use SL::Locale::String qw(t8);
+use SL::Util qw(trim);
+
+sub auth { undef }
+
+sub name { 'phone_number' }
+
+sub description_config { t8('All phone numbers') }
+
+sub description_field { t8('All phone numbers') }
+
+sub query_autocomplete {
+  my ($self) = @_;
+
+  my @results;
+  my $search_term = trim($::form->{term});
+  $search_term    =~ s{\p{WSpace}+}{}g;
+  $search_term    = join ' *', split(//, $search_term);
+
+  foreach my $model (qw(Customer Vendor)) {
+    my $manager = 'SL::DB::Manager::' . $model;
+    my $result  = $manager->get_all(
+      query => [ or => [ 'obsolete' => 0, 'obsolete' => undef ],
+                 or => [ phone                     => { imatch => $search_term },
+                         fax                       => { imatch => $search_term },
+                         'contacts.cp_phone1'      => { imatch => $search_term },
+                         'contacts.cp_phone2'      => { imatch => $search_term },
+                         'contacts.cp_fax'         => { imatch => $search_term },
+                         'contacts.cp_mobile1'     => { imatch => $search_term },
+                         'contacts.cp_mobile2'     => { imatch => $search_term },
+                         'contacts.cp_satphone'    => { imatch => $search_term },
+                         'contacts.cp_satfax'      => { imatch => $search_term },
+                         'contacts.cp_privatphone' => { imatch => $search_term },
+                 ] ],
+      with_objects => ['contacts']);
+
+    push @results, map {
+      value => $_->displayable_name,
+      label => $_->displayable_name,
+      id    => lc($model) . '_' . $_->id,
+    }, @$result;
+  }
+
+  return \@results;
+}
+
+sub select_autocomplete {
+  my ($self) = @_;
+
+  if ($::form->{id} =~ m{^(customer|vendor)_(\d+)$}) {
+    my $type      = $1;
+    my $id        = $2;
+    $::form->{id} = $id;
+
+    if ($type eq 'customer') {
+      SL::Controller::TopQuickSearch::Customer->new->select_autocomplete;
+    } elsif ($type eq 'vendor') {
+      SL::Controller::TopQuickSearch::Vendor->new->select_autocomplete;
+    }
+  }
+}
+
+sub do_search {
+  my ($self) = @_;
+
+  my $results = $self->query_autocomplete;
+
+  if (@$results == 1) {
+    $::form->{id} = $results->[0]{id};
+    return $self->select_autocomplete;
+  }
+}
+
+# TODO: result overview page
+
+1;
index 0c26dd1..e561360 100644 (file)
@@ -5,7 +5,7 @@ use parent qw(SL::Controller::TopQuickSearch::DeliveryOrder);
 
 use SL::Locale::String qw(t8);
 
-sub auth { 'purchase_delivery_order_edit' }
+sub auth { 'purchase_delivery_order_edit | purchase_delivery_order_edit' }
 
 sub name { 'purchase_delivery_order' }
 
index 4013c8a..f64fb83 100644 (file)
@@ -5,7 +5,7 @@ use parent qw(SL::Controller::TopQuickSearch::OERecord);
 
 use SL::Locale::String qw(t8);
 
-sub auth { 'purchase_order_edit' }
+sub auth { 'purchase_order_edit | purchase_order_view' }
 
 sub name { 'purchase_order' }
 
index 3b2adef..d957100 100644 (file)
@@ -5,7 +5,7 @@ use parent qw(SL::Controller::TopQuickSearch::OERecord);
 
 use SL::Locale::String qw(t8);
 
-sub auth { 'request_quotation_edit' }
+sub auth { 'request_quotation_edit | request_quotation_view' }
 
 sub name { 'request_quotation' }
 
index 4895b88..073a9c2 100644 (file)
@@ -5,7 +5,7 @@ use parent qw(SL::Controller::TopQuickSearch::DeliveryOrder);
 
 use SL::Locale::String qw(t8);
 
-sub auth { 'sales_delivery_order_edit' }
+sub auth { 'sales_delivery_order_edit | sales_delivery_order_view' }
 
 sub name { 'sales_delivery_order' }
 
index 1f5296e..8f91e6e 100644 (file)
@@ -5,7 +5,7 @@ use parent qw(SL::Controller::TopQuickSearch::OERecord);
 
 use SL::Locale::String qw(t8);
 
-sub auth { 'sales_order_edit' }
+sub auth { 'sales_order_edit | sales_order_view' }
 
 sub name { 'sales_order' }
 
index 28ec9fd..f7a6b77 100644 (file)
@@ -5,7 +5,7 @@ use parent qw(SL::Controller::TopQuickSearch::OERecord);
 
 use SL::Locale::String qw(t8);
 
-sub auth { 'sales_quotation_edit' }
+sub auth { 'sales_quotation_edit | sales_quotation_view' }
 
 sub name { 'sales_quotation' }
 
index 1db417c..86cb729 100644 (file)
@@ -543,6 +543,7 @@ sub generate_datev_data {
          $gl_itime_filter
          $gl_department_id_filter
          $gl_imported
+         AND NOT EXISTS (SELECT gl_id from ap_gl where gl_id = gl.id)
          $filter
 
        ORDER BY trans_id, acc_trans_id|;
@@ -835,6 +836,7 @@ sub generate_datev_lines {
       }
       if ($transaction->[$i]->{'taxkey'}) {
         $taxkey = $transaction->[$i]->{'taxkey'};
+        # $taxkey = 0 if $taxkey == 94; # taxbookings are in gl
       }
       if ($transaction->[$i]->{'charttax'}) {
         $charttax = $transaction->[$i]->{'charttax'};
diff --git a/SL/DB/AdditionalBillingAddress.pm b/SL/DB/AdditionalBillingAddress.pm
new file mode 100644 (file)
index 0000000..c6ffad4
--- /dev/null
@@ -0,0 +1,59 @@
+package SL::DB::AdditionalBillingAddress;
+
+use strict;
+
+use SL::DB::MetaSetup::AdditionalBillingAddress;
+use SL::DB::Manager::AdditionalBillingAddress;
+
+__PACKAGE__->meta->initialize;
+
+__PACKAGE__->after_save('_after_save_ensure_only_one_marked_as_default_per_customer');
+
+sub _after_save_ensure_only_one_marked_as_default_per_customer {
+  my ($self) = @_;
+
+  if ($self->id && $self->customer_id && $self->default_address) {
+    SL::DB::Manager::AdditionalBillingAddress->update_all(
+      set   => { default_address => 0 },
+      where => [
+        customer_id => $self->customer_id,
+        '!id'       => $self->id,
+      ],
+    );
+  }
+
+  return 1;
+}
+
+sub displayable_id {
+  my $self = shift;
+  my $text = join('; ', grep { $_ } (map({ $self->$_ } qw(name street)),
+                                     join(' ', grep { $_ }
+                                               map  { $self->$_ }
+                                               qw(zipcode city))));
+
+  return $text;
+}
+
+sub used {
+  my ($self) = @_;
+
+  return unless $self->id;
+
+  require SL::DB::Order;
+  require SL::DB::Invoice;
+  require SL::DB::DeliveryOrder;
+
+  my %args = (query => [ billing_address_id => $self->id ]);
+
+  return SL::DB::Manager::Invoice->get_all_count(%args)
+      || SL::DB::Manager::Order->get_all_count(%args)
+      || SL::DB::Manager::DeliveryOrder->get_all_count(%args);
+}
+
+sub detach {
+  $_[0]->customer_id(undef);
+  return $_[0];
+}
+
+1;
diff --git a/SL/DB/ApGl.pm b/SL/DB/ApGl.pm
new file mode 100644 (file)
index 0000000..77368a3
--- /dev/null
@@ -0,0 +1,13 @@
+# This file has been auto-generated only because it didn't exist.
+# Feel free to modify it at will; it will not be overwritten automatically.
+
+package SL::DB::ApGl;
+
+use strict;
+
+use SL::DB::MetaSetup::ApGl;
+use SL::DB::Manager::ApGl;
+
+__PACKAGE__->meta->initialize;
+
+1;
index e8c98cb..b07cdf1 100644 (file)
@@ -99,13 +99,16 @@ sub get_agreement_with_invoice {
   $bank_code      = $invoice->vendor->bank_code        if ! $invoice->is_sales;
   $iban           = $invoice->vendor->iban             if ! $invoice->is_sales;
   $account_number = $invoice->vendor->account_number   if ! $invoice->is_sales;
-  if ( $bank_code eq $self->remote_bank_code && $account_number eq $self->remote_account_number ) {
-    $agreement += $points{remote_account_number};
-    $rule_matches .= 'remote_account_number(' . $points{'remote_account_number'} . ') ';
-  }
-  if ( $iban eq $self->remote_account_number ) {
-    $agreement += $points{remote_account_number};
-    $rule_matches .= 'remote_account_number(' . $points{'remote_account_number'} . ') ';
+
+  # check only valid remote_account_number (with some content)
+  if ($self->remote_account_number) {
+    if ($bank_code eq $self->remote_bank_code && $account_number eq $self->remote_account_number) {
+      $agreement += $points{remote_account_number};
+      $rule_matches .= 'remote_account_number(' . $points{'remote_account_number'} . ') ';
+    } elsif ($iban eq $self->remote_account_number) { # elsif -> do not add twice
+      $agreement += $points{remote_account_number};
+      $rule_matches .= 'remote_account_number(' . $points{'remote_account_number'} . ') ';
+    }
   }
 
   my $datediff = $self->transdate->{utc_rd_days} - $invoice->transdate->{utc_rd_days};
index cb6c831..eeae39a 100644 (file)
@@ -52,7 +52,7 @@ sub parse_value {
     return $self->timestamp_value(!defined($unparsed) ? undef : ref($unparsed) eq 'DateTime' ? $unparsed->clone : DateTime->from_kivitendo($unparsed));
   }
 
-  # text, textfield, select
+  # text, textfield, htmlfield and select
   $self->text_value($unparsed);
 }
 
@@ -92,7 +92,7 @@ sub value {
     return $self->timestamp_value ? $self->timestamp_value->clone->truncate(to => 'day') : undef;
   }
 
-  goto &text_value; # text, textfield and select
+  goto &text_value; # text, textfield, htmlfield and select
 }
 
 sub value_as_text {
@@ -116,7 +116,7 @@ sub value_as_text {
     return $object ? $object->displayable_name : '';
   }
 
-  goto &text_value; # text, textfield and select
+  goto &text_value; # text, textfield, htmlfield and select
 }
 
 sub is_valid {
index f8bf7a1..6ba2238 100644 (file)
@@ -37,8 +37,8 @@ sub validate {
 use constant OPTION_DEFAULTS =>
   {
     MAXLENGTH => 75,
-    WIDTH => 30,
-    HEIGHT => 5,
+    WIDTH     => 225,
+    HEIGHT    => 90,
   };
 
 sub processed_options {
@@ -117,6 +117,7 @@ sub value_col {
     customer  => 'number_value',
     vendor    => 'number_value',
     part      => 'number_value',
+    htmlfield => 'text_value',
     text      => 'text_value',
     textfield => 'text_value',
     select    => 'text_value'
index 71c762a..d72d0c9 100644 (file)
@@ -2,6 +2,7 @@ package SL::DB::Customer;
 
 use strict;
 
+use List::Util qw(first);
 use Rose::DB::Object::Helpers qw(as_tree);
 
 use SL::Locale::String qw(t8);
@@ -29,6 +30,12 @@ use SL::DB::Helper::DisplayableNamePreferences (
 use SL::DB::VC;
 
 __PACKAGE__->meta->add_relationship(
+  additional_billing_addresses => {
+    type         => 'one to many',
+    class        => 'SL::DB::AdditionalBillingAddress',
+    column_map   => { id      => 'customer_id' },
+    manager_args => { sort_by => 'lower(additional_billing_addresses.name)' },
+  },
   shipto => {
     type         => 'one to many',
     class        => 'SL::DB::Shipto',
@@ -108,4 +115,11 @@ sub create_zugferd_invoices_for_this_customer {
   return $self->create_zugferd_invoices;
 }
 
+sub default_billing_address {
+  my $self = shift;
+
+  die 'not an accessor' if @_ > 1;
+  return first { $_->default_address } @{ $self->additional_billing_addresses };
+}
+
 1;
index 395a449..45d6588 100644 (file)
@@ -17,6 +17,8 @@ use SL::DB::Helper::TransNumberGenerator;
 use SL::DB::Part;
 use SL::DB::Unit;
 
+use SL::DB::DeliveryOrder::TypeData qw(:types);
+
 use SL::Helper::Number qw(_format_total _round_total);
 
 use List::Util qw(first);
@@ -77,7 +79,11 @@ sub sales_order {
 }
 
 sub type {
-  return shift->customer_id ? 'sales_delivery_order' : 'purchase_delivery_order';
+  goto &order_type;
+}
+
+sub is_type {
+  return shift->type eq shift;
 }
 
 sub displayable_type {
@@ -105,6 +111,10 @@ sub date {
   goto &transdate;
 }
 
+sub number {
+  goto &donumber;
+}
+
 sub _clone_orderitem_cvar {
   my ($cvar) = @_;
 
@@ -127,11 +137,11 @@ sub new_from {
   }
 
   my %args = ( map({ ( $_ => $source->$_ ) } qw(cp_id currency_id customer_id cusordnumber delivery_term_id department_id employee_id globalproject_id intnotes language_id notes
-                                                ordnumber payment_id reqdate salesman_id shippingpoint shipvia taxincluded taxzone_id transaction_description vendor_id
+                                                ordnumber payment_id reqdate salesman_id shippingpoint shipvia taxincluded taxzone_id transaction_description vendor_id billing_address_id
                                              )),
                closed    => 0,
-               is_sales  => !!$source->customer_id,
                delivered => 0,
+               order_type => $params{type},
                transdate => DateTime->today_local,
             );
 
@@ -146,12 +156,19 @@ sub new_from {
     $args{shipto_id} = $source->shipto_id;
   }
 
+  # infer type from legacy fields if not given
+  $args{order_type} //= $source->customer_id ? 'sales_delivery_order'
+                      : $source->vendor_id   ? 'purchase_delivery_order'
+                      : $source->is_sales    ? 'sales_delivery_order'
+                      : croak "need some way to set delivery order type from source";
+
   my $delivery_order = $class->new(%args);
   $delivery_order->assign_attributes(%{ $params{attributes} }) if $params{attributes};
   my $items          = delete($params{items}) || $source->items_sorted;
   my %item_parents;
 
-  my @items = map {
+  # do not copy items when converting to supplier delivery order
+  my @items = $delivery_order->is_type(SUPPLIER_DELIVERY_ORDER_TYPE) ? () : map {
     my $source_item      = $_;
     my $source_item_id   = $_->$item_parent_id_column;
     my @custom_variables = map { _clone_orderitem_cvar($_) } @{ $source_item->custom_variables };
@@ -287,6 +304,7 @@ sub new_from_time_recordings {
   } else {
     my %args = (
       is_sales    => 1,
+      order_type  => 'sales_delivery_order',
       delivered   => 0,
       customer_id => $sources->[0]->customer_id,
       taxzone_id  => $sources->[0]->customer->taxzone_id,
@@ -302,8 +320,17 @@ sub new_from_time_recordings {
   return $delivery_order;
 }
 
+# legacy for compatibility
+# use type_data cusomtervendor and transfer direction instead
+sub is_sales {
+  if ($_[0]->order_type) {
+   return SL::DB::DeliveryOrder::TypeData::get3($_[0]->order_type, "properties", "is_customer");
+  }
+  return $_[0]{is_sales};
+}
+
 sub customervendor {
-  $_[0]->is_sales ? $_[0]->customer : $_[0]->vendor;
+  SL::DB::DeliveryOrder::TypeData::get3($_[0]->order_type, "properties", "is_customer") ? $_[0]->customer : $_[0]->vendor;
 }
 
 sub convert_to_invoice {
diff --git a/SL/DB/DeliveryOrder/TypeData.pm b/SL/DB/DeliveryOrder/TypeData.pm
new file mode 100644 (file)
index 0000000..8b523fb
--- /dev/null
@@ -0,0 +1,200 @@
+package SL::DB::DeliveryOrder::TypeData;
+
+use strict;
+use Carp;
+use Exporter qw(import);
+use Scalar::Util qw(weaken);
+use SL::Locale::String qw(t8);
+
+use constant {
+  SALES_DELIVERY_ORDER_TYPE    => 'sales_delivery_order',
+  PURCHASE_DELIVERY_ORDER_TYPE => 'purchase_delivery_order',
+  SUPPLIER_DELIVERY_ORDER_TYPE => 'supplier_delivery_order',
+  RMA_DELIVERY_ORDER_TYPE      => 'rma_delivery_order',
+};
+
+my @export_types = qw(SALES_DELIVERY_ORDER_TYPE PURCHASE_DELIVERY_ORDER_TYPE SUPPLIER_DELIVERY_ORDER_TYPE RMA_DELIVERY_ORDER_TYPE);
+my @export_subs = qw(valid_types validate_type is_valid_type get get3);
+
+our @EXPORT_OK = (@export_types, @export_subs);
+our %EXPORT_TAGS = (types => \@export_types, subs => \@export_subs);
+
+my %type_data = (
+  SALES_DELIVERY_ORDER_TYPE() => {
+    text => {
+      delete => t8('Delivery Order has been deleted'),
+      saved  => t8('Delivery Order has been saved'),
+      add    => t8("Add Sales Delivery Order"),
+      edit   => t8("Edit Sales Delivery Order"),
+      attachment => t8("sales_delivery_order_list"),
+    },
+    show_menu => {
+      save_and_quotation      => 0,
+      save_and_rfq            => 0,
+      save_and_sales_order    => 0,
+      save_and_purchase_order => 0,
+      save_and_delivery_order => 0,
+      save_and_ap_transaction => 0,
+      save_and_invoice        => 0,
+      delete                  => sub { $::instance_conf->get_sales_delivery_order_show_delete },
+      new_controller          => 0,
+    },
+    properties => {
+      customervendor => "customer",
+      is_customer    => 1,
+      nr_key         => "donumber",
+      transfer       => 'out',
+      transnumber    => 'sdonumber',
+    },
+    part_classification_query => [ "used_for_sale" => 1 ],
+    rights => {
+      edit => "sales_delivery_order_edit",
+      view => "sales_delivery_order_edit | sales_delivery_order_view",
+    },
+  },
+  PURCHASE_DELIVERY_ORDER_TYPE() => {
+    text => {
+      delete => t8('Delivery Order has been deleted'),
+      saved  => t8('Delivery Order has been saved'),
+      add    => t8("Add Purchase Delivery Order"),
+      edit   => t8("Edit Purchase Delivery Order"),
+      attachment => t8("purchase_delivery_order_list"),
+    },
+    show_menu => {
+      save_and_quotation      => 0,
+      save_and_rfq            => 0,
+      save_and_sales_order    => 0,
+      save_and_purchase_order => 0,
+      save_and_delivery_order => 0,
+      save_and_ap_transaction => 0,
+      save_and_invoice        => 0,
+      delete                  => sub { $::instance_conf->get_sales_delivery_order_show_delete },
+      new_controller          => 0,
+    },
+    properties => {
+      customervendor => "vendor",
+      is_customer    => 0,
+      nr_key         => "donumber",
+      transfer       => 'in',
+      transnumber    => 'pdonumber',
+    },
+    part_classification_query => [ "used_for_purchase" => 1 ],
+    rights => {
+      edit => "purchase_delivery_order_edit",
+      view => "purchase_delivery_order_edit | purchase_delivery_order_view",
+    },
+  },
+  SUPPLIER_DELIVERY_ORDER_TYPE() => {
+    text => {
+      delete => t8('Supplier Delivery Order has been deleted'),
+      saved  => t8('Supplier Delivery Order has been saved'),
+      add    => t8("Add Supplier Delivery Order"),
+      edit   => t8("Edit Supplier Delivery Order"),
+      attachment => t8("supplier_delivery_order_list"),
+    },
+    show_menu => {
+      save_and_quotation      => 0,
+      save_and_rfq            => 0,
+      save_and_sales_order    => 0,
+      save_and_purchase_order => 0,
+      save_and_delivery_order => 0,
+      save_and_ap_transaction => 0,
+      save_and_invoice        => 0,
+      delete                  => sub { $::instance_conf->get_sales_delivery_order_show_delete },
+      new_controller          => 1,
+    },
+    properties => {
+      customervendor => "vendor",
+      is_customer    => 0,
+      nr_key         => "donumber",
+      transfer       => 'out',
+      transnumber    => 'sudonumber',
+    },
+    part_classification_query => [ "used_for_purchase" => 1 ],
+    rights => {
+      edit => "purchase_delivery_order_edit",
+      view => "purchase_delivery_order_edit | purchase_delivery_order_view",
+    },
+  },
+  RMA_DELIVERY_ORDER_TYPE() => {
+    text => {
+      delete => t8('Delivery Order has been deleted'),
+      saved  => t8('Delivery Order has been saved'),
+      add    => t8("Add RMA Delivery Order"),
+      edit   => t8("Edit RMA Delivery Order"),
+      attachment => t8("rma_delivery_order_list"),
+    },
+    show_menu => {
+      save_and_quotation      => 0,
+      save_and_rfq            => 0,
+      save_and_sales_order    => 0,
+      save_and_purchase_order => 0,
+      save_and_delivery_order => 0,
+      save_and_ap_transaction => 0,
+      save_and_invoice        => 0,
+      delete                  => sub { $::instance_conf->get_sales_delivery_order_show_delete },
+      new_controller          => 1,
+    },
+    properties => {
+      customervendor => "customer",
+      is_customer    => 1,
+      nr_key         => "donumber",
+      transfer       => 'in',
+      transnumber    => 'rdonumber',
+    },
+    part_classification_query => [ "used_for_sale" => 1 ],
+    rights => {
+      edit => "sales_delivery_order_edit",
+      view => "sales_delivery_order_edit | sales_delivery_order_view",
+    },
+  },
+);
+
+my @valid_types = (
+  SALES_DELIVERY_ORDER_TYPE,
+  PURCHASE_DELIVERY_ORDER_TYPE,
+  SUPPLIER_DELIVERY_ORDER_TYPE,
+  RMA_DELIVERY_ORDER_TYPE,
+);
+
+my %valid_types = map { $_ => $_ } @valid_types;
+
+sub valid_types {
+  \@valid_types;
+}
+
+sub is_valid_type {
+  !!exists $type_data{$_[0]};
+}
+
+sub validate_type {
+  my ($type) = @_;
+
+  return $valid_types{$type} // croak "invalid type '$type'";
+}
+
+sub get {
+  my ($type, $key) = @_;
+
+  croak "invalid type '$type'" unless exists $type_data{$type};
+
+  my $ret = $type_data{$type}->{$key} // die "unknown property '$key'";
+
+  ref $ret eq 'CODE'
+    ? $ret->()
+    : $ret;
+}
+
+sub get3 {
+  my ($type, $topic, $key) = @_;
+
+  croak "invalid type '$type'" unless exists $type_data{$type};
+
+  my $ret = $type_data{$type}{$topic}{$key} // croak "unknown property '$key' in topic '$topic' for type '$type'";
+
+  ref $ret eq 'CODE'
+    ? $ret->()
+    : $ret;
+}
+
+1;
index 045e2e6..7850a64 100644 (file)
@@ -48,6 +48,12 @@ sub displayable_delivery_order_info {
          . " (" . $self->delivery_order->transdate->to_kivitendo . ")";
 };
 
+sub effective_project {
+  my ($self) = @_;
+
+  $self->project // $self->delivery_order->globalproject;
+}
+
 __END__
 
 =pod
index 97fb2a1..dc6f00d 100644 (file)
@@ -13,6 +13,11 @@ __PACKAGE__->meta->add_relationship(
     class        => 'SL::DB::Inventory',
     column_map   => { id => 'delivery_order_items_stock_id' },
   },
+  unit_obj => {
+    type         => 'many to one',
+    class        => 'SL::DB::Unit',
+    column_map   => { unit => 'name' },
+  },
 );
 
 __PACKAGE__->meta->initialize;
index 8da20c0..0c321b6 100644 (file)
@@ -27,4 +27,14 @@ sub safe_name {
   return $self->name || $self->login;
 }
 
+sub auth_user {
+  my ($self) = @_;
+
+  die 'not an accessor' if scalar(@_) > 1;
+
+  require SL::DB::AuthUser;
+
+  return SL::DB::Manager::AuthUser->find_by(login => $self->login);
+}
+
 1;
index 615f8d1..0405b74 100644 (file)
@@ -8,6 +8,14 @@ use strict;
 use SL::DB::MetaSetup::File;
 use SL::DB::Manager::File;
 
+__PACKAGE__->meta->add_relationship(
+  full_text            => {
+    type               => 'one to one',
+    class              => 'SL::DB::FileFullText',
+    column_map         => { id => 'file_id' },
+  },
+);
+
 __PACKAGE__->meta->initialize;
 
 
diff --git a/SL/DB/FileFullText.pm b/SL/DB/FileFullText.pm
new file mode 100644 (file)
index 0000000..6c6cff4
--- /dev/null
@@ -0,0 +1,13 @@
+# This file has been auto-generated only because it didn't exist.
+# Feel free to modify it at will; it will not be overwritten automatically.
+
+package SL::DB::FileFullText;
+
+use strict;
+
+use SL::DB::MetaSetup::FileFullText;
+use SL::DB::Manager::FileFullText;
+
+__PACKAGE__->meta->initialize;
+
+1;
index 50b29c0..1dbf2c8 100644 (file)
@@ -2,6 +2,7 @@ package SL::DB::GLTransaction;
 
 use strict;
 
+use SL::DB::Helper::LinkedRecords;
 use SL::DB::MetaSetup::GLTransaction;
 use SL::Locale::String qw(t8);
 use List::Util qw(sum);
@@ -113,7 +114,7 @@ sub add_chart_booking {
   require SL::DB::Chart;
   die "add_chart_booking needs a transdate" unless $self->transdate;
   die "add_chart_booking needs taxincluded" unless defined $self->taxincluded;
-  die "chart missing"  unless $params{chart} && ref($params{chart}) eq 'SL::DB::Chart';
+  die "chart missing" unless $params{chart} && ref($params{chart}) eq 'SL::DB::Chart';
   die t8('Booking needs at least one debit and one credit booking!')
     unless $params{debit} or $params{credit}; # must exist and not be 0
   die t8('Cannot have a value in both Debit and Credit!')
@@ -212,7 +213,7 @@ sub validate {
       my $sum = sum map { $_->amount } @{ $self->transactions };
       # compare rounded amount to 0, to get around floating point problems, e.g.
       # $sum = -2.77555756156289e-17
-      push @errors, t8('Out of balance transaction!') unless $::form->round_amount($sum,5) == 0;
+      push @errors, t8('Out of balance transaction!') . $sum unless $::form->round_amount($sum,5) == 0;
     };
   } else {
     push @errors, t8('Empty transaction!');
index e0ab578..93848a0 100644 (file)
@@ -3,6 +3,8 @@ package SL::DB::Helper::ALL;
 use strict;
 
 use SL::DB::AccTransaction;
+use SL::DB::AdditionalBillingAddress;
+use SL::DB::ApGl;
 use SL::DB::Assembly;
 use SL::DB::AssortmentItem;
 use SL::DB::AuthClient;
@@ -45,6 +47,7 @@ use SL::DB::Customer;
 use SL::DB::Datev;
 use SL::DB::Default;
 use SL::DB::DeliveryOrder;
+use SL::DB::DeliveryOrder::TypeData;
 use SL::DB::DeliveryOrderItem;
 use SL::DB::DeliveryOrderItemsStock;
 use SL::DB::DeliveryTerm;
@@ -58,6 +61,7 @@ use SL::DB::Employee;
 use SL::DB::EmployeeProjectInvoices;
 use SL::DB::Exchangerate;
 use SL::DB::File;
+use SL::DB::FileFullText;
 use SL::DB::Finanzamt;
 use SL::DB::FollowUp;
 use SL::DB::FollowUpAccess;
index f999939..591073e 100644 (file)
@@ -15,7 +15,7 @@ sub flatten_to_form {
   _copy($self, $form, '', '', 0, qw(id type taxzone_id ordnumber quonumber invnumber donumber cusordnumber taxincluded shippingpoint shipvia notes intnotes cp_id
                                     employee_id salesman_id closed department_id language_id payment_id delivery_customer_id delivery_vendor_id shipto_id proforma
                                     globalproject_id delivered transaction_description container_type accepted_by_customer invoice storno storno_id dunning_config_id
-                                    orddate quodate reqdate gldate duedate deliverydate datepaid transdate tax_point delivery_term_id));
+                                    orddate quodate reqdate gldate duedate deliverydate datepaid transdate tax_point delivery_term_id billing_address_id));
   $form->{currency} = $form->{curr} = $self->currency_id ? $self->currency->name || '' : '';
 
   if ( $vc eq 'customer' ) {
index adc3dac..4614e5a 100644 (file)
@@ -315,6 +315,7 @@ sub sort_linked_records {
                   'SL::DB::ShopOrder'       => sub { $_[0]->shop_ordernumber },
                   'SL::DB::EmailJournal'    => sub { $_[0]->id },
                   'SL::DB::Dunning'         => sub { $_[0]->dunning_id },
+                  'SL::DB::GLTransaction'   => sub { $_[0]->reference },
                   UNKNOWN                   => '9999999999999999',
                 );
   my $number_xtor = sub {
@@ -342,7 +343,7 @@ sub sort_linked_records {
               purchase_order            => 130,
               purchase_delivery_order   => 140,
               'SL::DB::PurchaseInvoice' => 150,
-              'SL::DB::PurchaseInvoice' => 150,
+              'SL::DB::GLTransaction'   => 170,
               'SL::DB::Letter'          => 200,
               'SL::DB::ShopOrder'       => 250,
               'SL::DB::EmailJournal'    => 300,
index 5fc6855..bc477fc 100644 (file)
@@ -84,6 +84,7 @@ my @kivitendo_blacklist = (@kivitendo_blacklist_permanent, @kivitendo_blacklist_
 my %kivitendo_package_names = (
   # TABLE                           # MODEL (given in C style)
   acc_trans                      => 'acc_transaction',
+  additional_billing_addresses   => 'additional_billing_address',
   'auth.clients'                 => 'auth_client',
   'auth.clients_users'           => 'auth_client_user',
   'auth.clients_groups'          => 'auth_client_group',
@@ -98,6 +99,7 @@ my %kivitendo_package_names = (
   'auth.user_group'              => 'auth_user_group',
   ar                             => 'invoice',
   ap                             => 'purchase_invoice',
+  ap_gl                          => 'ap_gl',
   assembly                       => 'assembly',
   assortment_items               => 'assortment_item',
   background_jobs                => 'background_job',
@@ -142,6 +144,7 @@ my %kivitendo_package_names = (
   employee_project_invoices      => 'EmployeeProjectInvoices',
   exchangerate                   => 'exchangerate',
   files                          => 'file',
+  file_full_texts                => 'file_full_text',
   finanzamt                      => 'finanzamt',
   follow_up_access               => 'follow_up_access',
   follow_up_links                => 'follow_up_link',
index 6dee091..6d624fa 100644 (file)
@@ -4,20 +4,23 @@ use strict;
 
 use parent qw(Exporter);
 our @EXPORT = qw(pay_invoice);
-our @EXPORT_OK = qw(skonto_date skonto_charts amount_less_skonto within_skonto_period percent_skonto reference_account reference_amount open_amount open_percent remaining_skonto_days skonto_amount check_skonto_configuration valid_skonto_amount get_payment_suggestions validate_payment_type open_sepa_transfer_amount get_payment_select_options_for_bank_transaction exchangerate forex);
+our @EXPORT_OK = qw(skonto_date amount_less_skonto within_skonto_period percent_skonto reference_account reference_amount open_amount open_percent remaining_skonto_days skonto_amount check_skonto_configuration valid_skonto_amount get_payment_suggestions validate_payment_type open_sepa_transfer_amount get_payment_select_options_for_bank_transaction exchangerate forex _skonto_charts_and_tax_correction);
 our %EXPORT_TAGS = (
   "ALL" => [@EXPORT, @EXPORT_OK],
 );
 
 require SL::DB::Chart;
+
+use Carp;
 use Data::Dumper;
 use DateTime;
-use SL::DATEV qw(:CONSTANTS);
-use SL::Locale::String qw(t8);
 use List::Util qw(sum);
+
+use SL::DATEV qw(:CONSTANTS);
 use SL::DB::Exchangerate;
 use SL::DB::Currency;
-use Carp;
+use SL::HTML::Util;
+use SL::Locale::String qw(t8);
 
 #
 # Public functions not exported by default
@@ -38,25 +41,35 @@ sub pay_invoice {
   validate_payment_type($params{payment_type});
 
   # check for required parameters and optional params depending on payment_type
-  Common::check_params(\%params, qw(chart_id transdate));
+  Common::check_params(\%params, qw(chart_id transdate amount));
+  Common::check_params(\%params, qw(bt_id)) unless $params{payment_type} eq 'without_skonto';
+
+  # three valid cases, test logical params in depth, before proceeding ...
   if ( $params{'payment_type'} eq 'without_skonto' && abs($params{'amount'}) < 0) {
     croak "invalid amount for payment_type 'without_skonto': $params{'amount'}\n";
-  }
-  if ($params{'payment_type'} eq 'free_skonto') {
+  } elsif ($params{'payment_type'} eq 'free_skonto') {
     # we dont like too much automagic for this payment type.
     # we force caller input for amount and skonto amount
-    Common::check_params(\%params, qw(amount skonto_amount));
+    Common::check_params(\%params, qw(skonto_amount));
     # secondly we dont want to handle credit notes and purchase credit notes
-    croak("Cannot use 'free skonto' for credit or debit notes") if ($params{amount} <= 0 || $params{skonto_amount} <= 0);
+    croak("Cannot use 'free skonto' for credit or debit notes") if ($params{amount} < 0 || $params{skonto_amount} <= 0);
     # both amount have to be rounded
     $params{skonto_amount} = _round($params{skonto_amount});
     $params{amount}        = _round($params{amount});
-    # lastly skonto_amount has to be smaller than the open invoice amount or payment amount ;-)
-    if ($params{skonto_amount} > abs($self->open_amount) || $params{skonto_amount} > $params{amount}) {
-      croak("Skonto amount higher than the payment or invoice amount");
+    # lastly skonto_amount has to be smaller or equal than the open invoice amount
+    if ($params{skonto_amount} > _round($self->open_amount)) {
+      croak("Skonto amount:" . $params{skonto_amount} . " higher than the payment or open invoice amount:" . $self->open_amount);
     }
+  } elsif ( $params{'payment_type'} eq 'with_skonto_pt' ) {
+    # options with_skonto_pt doesn't require the parameter
+    # amount, but if amount is passed, make sure it matches the expected value
+    # note: the parameter isn't used at all - amount_less_skonto will always be used
+    # partial skonto payments are therefore impossible to book
+    croak "amount $params{amount} doesn't match amount less skonto: " . $self->amount_less_skonto . "\n" if $params{amount} && abs($self->amount_less_skonto - $params{amount} ) > 0.0000001;
+    croak "payment type with_skonto_pt can't be used if payments have already been made" if $self->paid != 0;
   }
 
+
   my $transdate_obj;
   if (ref($params{transdate}) eq 'DateTime') {
     $transdate_obj = $params{transdate};
@@ -77,8 +90,9 @@ sub pay_invoice {
   };
 
   # currency is either passed or use the invoice currency if it differs from the default currency
+  # TODO remove
   my ($exchangerate,$currency);
-  if ($params{currency} || $params{currency_id} || $self->currency_id != $::instance_conf->get_currency_id) {
+  if ($params{currency} || $params{currency_id}) {
     if ($params{currency} || $params{currency_id} ) { # currency was specified
       $currency = SL::DB::Manager::Currency->find_by(name => $params{currency}) || SL::DB::Manager::Currency->find_by(id => $params{currency_id});
     } else { # use invoice currency
@@ -101,15 +115,6 @@ sub pay_invoice {
     $exchangerate = 1;
   };
 
-  # options with_skonto_pt and difference_as_skonto don't require the parameter
-  # amount, but if amount is passed, make sure it matches the expected value
-  if ( $params{'payment_type'} eq 'difference_as_skonto' ) {
-    croak "amount $params{amount} doesn't match open amount " . $self->open_amount . ", diff = " . ($params{amount}-$self->open_amount) if $params{amount} && abs($self->open_amount - $params{amount} ) > 0.0000001;
-  } elsif ( $params{'payment_type'} eq 'with_skonto_pt' ) {
-    croak "amount $params{amount} doesn't match amount less skonto: " . $self->amount_less_skonto . "\n" if $params{amount} && abs($self->amount_less_skonto - $params{amount} ) > 0.0000001;
-    croak "payment type with_skonto_pt can't be used if payments have already been made" if $self->paid != 0;
-  };
-
   # absolute skonto amount for invoice, use as reference sum to see if the
   # calculated skontos add up
   # only needed for payment_term "with_skonto_pt"
@@ -135,18 +140,15 @@ sub pay_invoice {
     my $new_acc_trans;
 
     # all three payment type create 1 AR/AP booking (the paid part)
-    # difference_as_skonto creates n skonto bookings (1 for each buchungsgruppe type)
-    # with_skonto_pt creates 1 bank booking and n skonto bookings (1 for each buchungsgruppe type)
+    # with_skonto_pt creates 1 bank booking and n skonto bookings (1 for each tax type)
+    # and one tax correction as a gl booking
     # without_skonto creates 1 bank booking
 
-    # as long as there is no automatic tax, payments are always booked with
-    # taxkey 0
-
-    unless ( $params{payment_type} eq 'difference_as_skonto' ) {
+    unless ( $rounded_params_amount == 0 ) {
       # cases with_skonto_pt, free_skonto and without_skonto
 
       # for case with_skonto_pt we need to know the corrected amount at this
-      # stage if we are going to use $params{amount}
+      # stage because we don't use $params{amount} ?!
 
       my $pay_amount = $rounded_params_amount;
       $pay_amount = $self->amount_less_skonto if $params{payment_type} eq 'with_skonto_pt';
@@ -211,26 +213,18 @@ sub pay_invoice {
         }
       }
     }
-    # better everything except without_skonto
-    if ($params{payment_type} eq 'difference_as_skonto' or $params{payment_type} eq 'with_skonto_pt'
-        or $params{payment_type} eq 'free_skonto' ) {
+    # skonto cases
+    if ($params{payment_type} eq 'with_skonto_pt' or $params{payment_type} eq 'free_skonto' ) {
 
       my $total_skonto_amount;
       if ( $params{payment_type} eq 'with_skonto_pt' ) {
         $total_skonto_amount = $self->skonto_amount;
-      } elsif ( $params{payment_type} eq 'difference_as_skonto' ) {
-        $total_skonto_amount = $self->open_amount;
       } elsif ( $params{payment_type} eq 'free_skonto') {
         $total_skonto_amount = $params{skonto_amount};
       }
-      my @skonto_bookings = $self->skonto_charts($total_skonto_amount);
-
-      # error checking:
-      if ( $params{payment_type} eq 'difference_as_skonto' ) {
-        my $calculated_skonto_sum  = sum map { $_->{skonto_amount} } @skonto_bookings;
-        croak "calculated skonto for difference_as_skonto = $calculated_skonto_sum doesn't add up open amount: " . $self->open_amount unless _round($calculated_skonto_sum) == _round($self->open_amount);
-      };
-
+      my @skonto_bookings = $self->_skonto_charts_and_tax_correction(amount => $total_skonto_amount, bt_id => $params{bt_id},
+                                                                     transdate_obj => $transdate_obj, memo => $params{memo},
+                                                                     source => $params{source});
       my $reference_amount = $total_skonto_amount;
 
       # create an acc_trans entry for each result of $self->skonto_charts
@@ -254,17 +248,11 @@ sub pay_invoice {
         $reference_amount -= abs($amount);
         $paid_amount      += -1 * $amount * $exchangerate;
         $skonto_amount_check -= $skonto_booking->{'skonto_amount'};
-      };
-      if ( $params{payment_type} eq 'difference_as_skonto' ) {
-          die "difference_as_skonto calculated incorrectly, sum of calculated payments doesn't add up to open amount $total_open_amount, reference_amount = $reference_amount\n" unless _round($reference_amount) == 0;
       }
     }
-
     my $arap_amount = 0;
 
-    if ( $params{payment_type} eq 'difference_as_skonto' ) {
-      $arap_amount = $total_open_amount;
-    } elsif ( $params{payment_type} eq 'without_skonto' ) {
+    if ( $params{payment_type} eq 'without_skonto' ) {
       $arap_amount = $rounded_params_amount;
     } elsif ( $params{payment_type} eq 'with_skonto_pt' ) {
       # this should be amount + sum(amount+skonto), but while we only allow
@@ -290,6 +278,67 @@ sub pay_invoice {
     $arap_booking->save;
     push @new_acc_ids, $arap_booking->acc_trans_id;
 
+    # hook for invoice_for_advance_payment DATEV always pairs, acc_trans_id has to be higher than arap_booking ;-)
+    if ($self->invoice_type eq 'invoice_for_advance_payment') {
+      my $clearing_chart = SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_clearing_chart_id)->load;
+      die "No Clearing Chart for Advance Payment" unless ref $clearing_chart eq 'SL::DB::Chart';
+
+      # what does ptc say
+      my %inv_calc = $self->calculate_prices_and_taxes();
+      my @trans_ids = keys %{ $inv_calc{amounts} };
+      die "Invalid state for advance payment more than one trans_id" if (scalar @trans_ids > 1);
+      my $entry = delete $inv_calc{amounts}{$trans_ids[0]};
+      my $tax;
+      if ($entry->{tax_id}) {
+        $tax = SL::DB::Manager::Tax->find_by(id => $entry->{tax_id}); # || die "Can't find tax with id " . $entry->{tax_id};
+      }
+      if ($tax and $tax->rate != 0) {
+        my ($netamount, $taxamount);
+        my $roundplaces = 2;
+        # we dont have a clue about skonto, that's why we use $arap_amount as taxincluded
+        ($netamount, $taxamount) = Form->calculate_tax($arap_amount, $tax->rate, 1, $roundplaces);
+        # for debugging database set
+        my $fullmatch = $netamount == $entry->{amount} ? '::netamount total true' : '';
+        my $transfer_chart = $tax->taxkey == 2 ? SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_taxable_7_id)->load
+                          :  $tax->taxkey == 3 ? SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_taxable_19_id)->load
+                          :  undef;
+        die "No Transfer Chart for Advance Payment" unless ref $transfer_chart eq 'SL::DB::Chart';
+
+        my $arap_full_booking= SL::DB::AccTransaction->new(trans_id   => $self->id,
+                                                           chart_id   => $clearing_chart->id,
+                                                           chart_link => $clearing_chart->link,
+                                                           amount     => $arap_amount * -1, # full amount
+                                                           transdate  => $transdate_obj,
+                                                           source     => 'Automatic Tax Booking for Payment in Advance' . $fullmatch,
+                                                           taxkey     => 0,
+                                                           tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
+        $arap_full_booking->save;
+        push @new_acc_ids, $arap_full_booking->acc_trans_id;
+
+        my $arap_tax_booking= SL::DB::AccTransaction->new(trans_id   => $self->id,
+                                                          chart_id   => $transfer_chart->id,
+                                                          chart_link => $transfer_chart->link,
+                                                          amount     => _round($netamount), # full amount
+                                                          transdate  => $transdate_obj,
+                                                          source     => 'Automatic Tax Booking for Payment in Advance' . $fullmatch,
+                                                          taxkey     => $tax->taxkey,
+                                                          tax_id     => $tax->id);
+        $arap_tax_booking->save;
+        push @new_acc_ids, $arap_tax_booking->acc_trans_id;
+
+        my $tax_booking= SL::DB::AccTransaction->new(trans_id   => $self->id,
+                                                     chart_id   => $tax->chart_id,
+                                                     chart_link => $tax->chart->link,
+                                                     amount     => _round($taxamount),
+                                                     transdate  => $transdate_obj,
+                                                     source     => 'Automatic Tax Booking for Payment in Advance' . $fullmatch,
+                                                     taxkey     => 0,
+                                                     tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
+
+        $tax_booking->save;
+        push @new_acc_ids, $tax_booking->acc_trans_id;
+      }
+    }
     $fx_gain_loss_amount *= -1 if $self->is_sales;
     $self->paid($self->paid + _round($paid_amount) + $fx_gain_loss_amount) if $paid_amount;
     $self->datepaid($transdate_obj);
@@ -504,110 +553,130 @@ sub open_sepa_transfer_amount {
 
   return $open_sepa_amount || 0;
 
-};
-
-
-sub skonto_charts {
-  my $self = shift;
-
-  # TODO: use param for amount, may also want to calculate skonto_amounts by
-  # passing percentage in the future
-
-  my $amount = shift || $self->skonto_amount;
-
-  croak "no amount passed to skonto_charts" unless abs(_round($amount)) >= 0.01;
-
-  # TODO: check whether there are negative values in invoice / acc_trans ... credited items
-
-  # don't check whether skonto applies, because user may want to override this
-  # return undef unless $self->percent_skonto;
-
-  my $is_sales = ref($self) eq 'SL::DB::Invoice';
-
-  my $mult = $is_sales ? 1 : -1;  # multiplier for getting the right sign
-
-  my @skonto_charts;  # resulting array with all income/expense accounts that have to be corrected
-
-  # calculate effective skonto (percentage) in difference_as_skonto mode
-  # only works if there are no negative acc_trans values
-  my $effective_skonto_rate = $amount ? $amount / $self->amount : 0;
-
-  # checks:
-  my $total_skonto_amount  = 0;
-  my $total_rounding_error = 0;
-
-  my $reference_ARAP_amount = 0;
-
-  # my $transactions = $self->transactions;
-  foreach my $transaction (@{ $self->transactions }) {
-    # find all transactions with an AR_amount or AP_amount link
-    $transaction->{chartlinks} = { map { $_ => 1 } split(m/:/, $transaction->{chart_link}) };
-    # second condition is that we can determine an automatic Skonto account for each AR_amount entry
+}
 
-    if ( ( $is_sales && $transaction->{chartlinks}->{AR_amount} ) or ( !$is_sales && $transaction->{chartlinks}->{AP_amount}) ) {
-        # $reference_ARAP_amount += $transaction->{amount} * $mult;
+sub _skonto_charts_and_tax_correction {
+  my ($self, %params)   = @_;
+  my $amount = $params{amount} || $self->skonto_amount;
 
-        # quick hack that works around problem of non-unique tax keys in SKR04
-        # ? use tax_id in acc_trans
-        my $tax = SL::DB::Manager::Tax->get_first( where => [id => $transaction->{tax_id}]);
-        croak "no tax for taxkey " . $transaction->{taxkey} unless ref $tax;
+  croak "no amount passed to skonto_charts"                    unless abs(_round($amount)) >= 0.01;
+  croak "no banktransaction.id passed to skonto_charts"        unless $params{bt_id};
+  croak "no banktransaction.transdate passed to skonto_charts" unless ref $params{transdate_obj} eq 'DateTime';
 
-        if ( $is_sales ) {
-          die t8('no skonto_chart configured for taxkey #1 : #2 : #3', $transaction->{taxkey} , $tax->taxdescription , $tax->rate*100) unless ref $tax->skonto_sales_chart;
-        } else {
-          die t8('no skonto_chart configured for taxkey #1 : #2 : #3', $transaction->{taxkey} , $tax->taxdescription , $tax->rate*100) unless ref $tax->skonto_purchase_chart;
-        };
+  $params{memo}   //= '';
+  $params{source} //= '';
 
-        my $skonto_amount_unrounded;
 
-        my $skonto_percent_abs = $self->amount ? abs($transaction->amount * (1 + $tax->rate) * 100 / $self->amount) : 0;
+  my $is_sales = $self->is_sales;
+  my (@skonto_charts, $inv_calc, $total_skonto_rounded);
 
-        my $transaction_amount = abs($transaction->{amount} * (1 + $tax->rate));
-        my $transaction_skonto_percent = abs($transaction_amount/$self->amount); # abs($transaction->{amount} * (1 + $tax->rate));
+  $inv_calc = $self->get_tax_and_amount_by_tax_chart_id();
 
+  # foreach tax.chart_id || $entry->{ta..id}
+  while (my ($tax_chart_id, $entry) = each %{ $inv_calc } ) {
+    my $tax = SL::DB::Manager::Tax->find_by(id => $entry->{tax_id}) || die "Can't find tax with id " . $tax_chart_id;
+    die t8('no skonto_chart configured for taxkey #1 : #2 : #3', $tax->taxkey, $tax->taxdescription , $tax->rate * 100)
+      unless $is_sales ? ref $tax->skonto_sales_chart : ref $tax->skonto_purchase_chart;
 
-        $skonto_amount_unrounded   = abs($amount * $transaction_skonto_percent);
-        my $skonto_amount_rounded  = _round($skonto_amount_unrounded);
-        my $rounding_error         = $skonto_amount_unrounded - $skonto_amount_rounded;
-        my $rounded_rounding_error = _round($rounding_error);
+    # percent net amount
+    my $transaction_net_skonto_percent = abs($entry->{netamount} / $self->amount);
+    my $skonto_netamount_unrounded     = abs($amount * $transaction_net_skonto_percent);
 
-        $total_rounding_error += $rounding_error;
-        $total_skonto_amount  += $skonto_amount_rounded;
+    # percent tax amount
+    my $transaction_tax_skonto_percent = abs($entry->{tax} / $self->amount);
+    my $skonto_taxamount_unrounded     = abs($amount * $transaction_tax_skonto_percent);
 
-        my $rec = {
-          # skonto_percent_abs: relative part of amount + tax to the total invoice amount
-          'skonto_percent_abs'     => $skonto_percent_abs,
-          'chart_id'               => $is_sales ? $tax->skonto_sales_chart->id : $tax->skonto_purchase_chart->id,
-          'skonto_amount'          => $skonto_amount_rounded,
-          # 'rounding_error'         => $rounding_error,
-          # 'rounded_rounding_error' => $rounded_rounding_error,
-        };
+    my $skonto_taxamount_rounded   = _round($skonto_taxamount_unrounded);
+    my $skonto_netamount_rounded   = _round($skonto_netamount_unrounded);
+    my $chart_id                   = $is_sales ? $tax->skonto_sales_chart->id : $tax->skonto_purchase_chart->id;
 
-        push @skonto_charts, $rec;
-      };
-  };
-
-  # if the rounded sum of all rounding_errors reaches 0.01 this sum is
-  # subtracted from the largest skonto_amount
-  my $rounded_total_rounding_error = abs(_round($total_rounding_error));
-
-  if ( $rounded_total_rounding_error > 0 ) {
-    my $highest_amount_pos = 0;
-    my $highest_amount = 0;
-    my $i = -1;
-    foreach my $ref ( @skonto_charts ) {
-      $i++;
-      if ( $ref->{skonto_amount} > $highest_amount ) {
-        $highest_amount     = $ref->{skonto_amount};
-        $highest_amount_pos = $i;
-      };
+    # entry net + tax for caller
+    my $rec_net = {
+      chart_id               => $chart_id,
+      skonto_amount          => _round($skonto_netamount_unrounded + $skonto_taxamount_unrounded),
     };
-    $skonto_charts[$i]->{skonto_amount} -= $rounded_total_rounding_error;
-  };
+    push @skonto_charts, $rec_net;
+    $total_skonto_rounded += $rec_net->{skonto_amount};
+
+    # add-on: correct tax with one linked gl booking
+
+    # no skonto tax correction for dual tax (reverse charge) or rate = 0 or taxamount below 0.01
+    next if ($tax->rate == 0 || $tax->reverse_charge_chart_id || $skonto_taxamount_rounded < 0.01);
+
+    my ($credit, $debit);
+    $credit = SL::DB::Manager::Chart->find_by(id => $chart_id);
+    $debit  = SL::DB::Manager::Chart->find_by(id => $tax_chart_id);
+    croak("No such Chart ID")  unless ref $credit eq 'SL::DB::Chart' && ref $debit eq 'SL::DB::Chart';
+    my $notes = SL::HTML::Util->strip($self->notes);
+
+    my $current_transaction = SL::DB::GLTransaction->new(
+         employee_id    => $self->employee_id,
+         transdate      => $params{transdate_obj},
+         notes          => $params{source} . ' ' . $params{memo},
+         description    => $notes || $self->invnumber,
+         reference      => t8('Skonto Tax Correction for') . " " . $tax->rate * 100 . '% ' . $self->invnumber,
+         department_id  => $self->department_id ? $self->department_id : undef,
+         imported       => 0, # not imported
+         taxincluded    => 0,
+      )->add_chart_booking(
+         chart  => $is_sales ? $debit : $credit,
+         debit  => abs($skonto_taxamount_rounded),
+         source => t8('Skonto Tax Correction for') . " " . $self->invnumber,
+         memo   => $params{memo},
+         tax_id => 0,
+      )->add_chart_booking(
+         chart  => $is_sales ? $credit : $debit,
+         credit => abs($skonto_taxamount_rounded),
+         source => t8('Skonto Tax Correction for') . " " . $self->invnumber,
+         memo   => $params{memo},
+         tax_id => 0,
+      )->post;
+
+    # add a stable link acc_trans_id to bank_transactions.id
+    foreach my $transaction (@{ $current_transaction->transactions }) {
+      my %props_acc = (
+           acc_trans_id        => $transaction->acc_trans_id,
+           bank_transaction_id => $params{bt_id},
+           gl                  => $current_transaction->id,
+      );
+      SL::DB::BankTransactionAccTrans->new(%props_acc)->save;
+    }
+    # Record a record link from banktransactions to gl
+    my %props_rl = (
+         from_table => 'bank_transactions',
+         from_id    => $params{bt_id},
+         to_table   => 'gl',
+         to_id      => $current_transaction->id,
+    );
+    SL::DB::RecordLink->new(%props_rl)->save;
+    # Record a record link from arap to gl
+    # linked gl booking will appear in tab linked records
+    # this is just a link for convenience
+    %props_rl = (
+         from_table => $is_sales ? 'ar' : 'ap',
+         from_id    => $self->id,
+         to_table   => 'gl',
+         to_id      => $current_transaction->id,
+    );
+    SL::DB::RecordLink->new(%props_rl)->save;
 
-  return @skonto_charts;
-};
+  }
+  # check for rounding errors, at least for the payment chart
+  # we ignore tax rounding errors as long as the amount (user input or calculated)
+  # is fully assigned.
+  # we simply alter one cent for the first skonto booking entry
+  # should be correct for most of the cases (no invoices with mixed taxes)
+  if (_round($total_skonto_rounded - $amount) >= 0.01) {
+    # subtract one cent
+    $skonto_charts[0]->{skonto_amount} -= 0.01;
+  } elsif (_round($amount - $total_skonto_rounded) >= 0.01) {
+    # add one cent
+    $skonto_charts[0]->{skonto_amount} += 0.01;
+  }
 
+  # return same array of skonto charts as sub skonto_charts
+  return @skonto_charts;
+}
 
 sub within_skonto_period {
   my $self = shift;
@@ -693,6 +762,8 @@ sub get_payment_suggestions {
       push(@{$self->{payment_select_options}} , { payment_type => 'with_skonto_pt',  display => t8('with skonto acc. to pt') , selected => 1 });
     } else {
       if ( ( $self->valid_skonto_amount($self->open_amount) || $self->valid_skonto_amount($open_amount) ) and not $params{sepa} ) {
+        # Will never be reached
+        die "This case is as dead as the dead cat. Go to start, don't pick 2,000 \$";
         $self->{invoice_amount_suggestion} = $open_amount;
         # only suggest difference_as_skonto if open_amount exactly matches skonto_amount
         # AND we aren't in SEPA mode
@@ -706,6 +777,8 @@ sub get_payment_suggestions {
     $self->{invoice_amount_suggestion} = $open_amount;
     # difference_as_skonto doesn't make any sense for SEPA transfer, as this doesn't cause any actual payment
     if ( $self->valid_skonto_amount($self->open_amount) && not $params{sepa} ) {
+      # probably also dead code
+      die "This case is as dead as the dead cat. Go to start, don't pick 2,000 \$";
       push(@{$self->{payment_select_options}} , { payment_type => 'difference_as_skonto',  display => t8('difference as skonto') , selected => 0 });
     };
   };
@@ -716,13 +789,12 @@ sub get_payment_suggestions {
 #
 # $main::locale->text('without_skonto')
 # $main::locale->text('with_skonto_pt')
-# $main::locale->text('difference_as_skonto')
 #
 
 sub validate_payment_type {
   my $payment_type = shift;
 
-  my %allowed_payment_types = map { $_ => 1 } qw(without_skonto with_skonto_pt difference_as_skonto free_skonto);
+  my %allowed_payment_types = map { $_ => 1 } qw(without_skonto with_skonto_pt free_skonto);
   croak "illegal payment type: $payment_type, must be one of: " . join(' ', keys %allowed_payment_types) unless $allowed_payment_types{ $payment_type };
 
   return 1;
@@ -769,16 +841,20 @@ Create a payment booking for an existing invoice object (type ar/ap/is/ir) via
 a configured bank account.
 
 This function deals with all the acc_trans entries and also updates paid and datepaid.
-The params C<transdate> and C<chart_id> are mandantory.
-If the default payment ('without_skonto') is used the param amount is also
-mandantory.
-If the payment type ('free_skonto') is used the number params skonto_amount and amount
-are as well mandantory and need to be positive. Furthermore the skonto amount has
-to be lower than the payment or open invoice amount.
+The params C<transdate>, C<amount> and C<chart_id> are mandantory.
+
+For all valid skonto types ('free_skonto' or 'with_skonto_pt') the source of
+the bank_transaction is needed, therefore pay_invoice expects the param
+C<bt_id> with a valid bank_transactions.id.
+
+If the payment type ('free_skonto') is used the number param skonto_amount is
+as well mandantory and needs to be positive. Furthermore the skonto amount has
+to be lower or equal than the open invoice amount.
+Payments with only skonto and zero bank transaction amount are possible.
 
 Transdate can either be a date object or a date string.
 Chart_id is the id of the payment booking chart.
-Amount is either a positive or negative number, but never 0.
+Amount is either a positive or negative number, and for the case 'free_skonto' might be zero.
 
 CAVEAT! The helper tries to get the sign right and all calls from BankTransaction are
 positive (abs($value)) values.
@@ -817,7 +893,7 @@ or in a certain currency:
                   );
 
 Allowed payment types are:
-  without_skonto with_skonto_pt difference_as_skonto
+  without_skonto with_skonto_pt
 
 The option C<payment_type> allows for a basic skonto mechanism.
 
@@ -831,36 +907,21 @@ booked according to the skonto chart configured in the tax settings for each
 tax key. If an amount is passed it is ignored and the actual configured skonto
 amount is used.
 
-C<difference_as_skonto> can only be used after partial payments have been made,
-the whole specified amount is booked according to the skonto charts configured
-in the tax settings for each tax key.
-
-So passing amount doesn't have any effect for the cases C<with_skonto_pt> and
-C<difference_as_skonto>, as all necessary values are taken from the stored
-invoice.
+So passing amount doesn't have any effect for the case C<with_skonto_pt>.
 
 The skonto modes automatically calculate the relative amounts for a mix of
 taxes, e.g. items with 7% and 19% in one invoice. There is a helper method
-skonto_charts, which calculates the relative percentages according to the
-amounts in acc_trans (which are grouped by tax).
+_skonto_charts_and_tax_correction, which calculates the relative percentages
+according to the amounts in acc_trans grouped by different tax rates.
+
+The helper method also generates the tax correction for the skonto booking
+and links this to the original bank transaction and the selected record.
 
 There is currently no way of excluding certain items in an invoice from having
 skonto applied to them.  If this feature was added to parts the calculation
 method of relative skonto would have to be completely rewritten using the
 invoice items rather than acc_trans.
 
-The skonto modes also still don't automatically correct the tax, this still has
-to be done manually. Therefore all payments generated by pay_invoice have
-taxkey 0.
-
-There is currently no way to directly pay an invoice via this method if the
-effective skonto differs from the skonto according to the payment terms
-configured for the invoice/vendor.
-
-In this case one has to pay in two steps: first the actual paid amount via
-"without skonto", and then the remainder via "difference_as_skonto". The user
-has to there actively decide whether to accept the differing skonto.
-
 Because of the way skonto_charts works the calculation doesn't work if there
 are negative values in acc_trans. E.g. one invoice with a positive value for
 19% tax and a negative value for the acc_trans line with 7%
@@ -873,7 +934,9 @@ If neither currency or currency_id are given as params, the currency of the
 invoice is assumed to be the payment currency.
 
 If successful the return value will be 1 in scalar context or in list context
-the two ids (acc_trans_id) of the newly created bookings.
+the two or more (gl transaction for skonto tax correction) ids (acc_trans_id)
+of the newly created bookings.
+
 
 =item C<reference_account>
 
@@ -929,7 +992,11 @@ Example:
    # ... do something
  }
 
-=item C<skonto_charts [$amount]>
+=item C<_skonto_charts_and_tax_correction [amount => $amount, bt_id => $bank_transaction.id, transdate_ojb => DateTime]>
+
+Needs a valid bank_transaction id and the transdate of the bank_transaction as
+a DateTime object.
+If no amout is passed, the currently open invoice amount will be used.
 
 Returns a list of chart_ids and some calculated numbers that can be used for
 paying the invoice with skonto. This function will automatically calculate the
@@ -938,10 +1005,13 @@ relative skonto amounts even if the invoice contains several types of taxes
 
 Example usage:
   my $invoice = SL::DB::Manager::Invoice->find_by(invnumber => '211');
-  my @skonto_charts = $invoice->skonto_charts;
+  my @skonto_charts = $invoice->_skonto_charts_and_tax_correction(bt_id         => $bt_id,
+                                                                  transdate_obj => $transdate_obj);
 
 or with the total skonto amount as an argument:
-  my @skonto_charts = $invoice->skonto_charts($invoice->open_amount);
+  my @skonto_charts = $invoice->_skonto_charts_and_tax_correction(amount => $invoice->open_amount,
+                                                                  bt_id  => $bt_id,
+                                                                  transdate_obj => $transdate_obj);
 
 The following values are generated for each chart:
 
@@ -955,57 +1025,12 @@ The chart id of the skonto amount to be booked.
 
 The total amount to be paid to the account
 
-=item C<skonto_percent>
-
-The relative percentage of that skonto chart. This can be useful if the actual
-ekonto that is paid deviates from the granted skonto, e.g. customer effectively
-pays 2.6% skonto instead of 2%, and we accept this. Then we can still calculate
-the relative skonto amounts for different taxes based on the absolute
-percentages. Used for case C<difference_as_skonto>.
-
-=item C<skonto_percent_abs>
-
-The absolute percentage of that skonto chart in relation to the total amount.
-Used to calculate skonto_amount for case C<with_skonto_pt>.
-
 =back
 
 If the invoice contains several types of taxes then skonto_charts can be used
 to calculate the relative amounts.
 
-Example in console of an invoice with 100 Euro at 7% and 100 Euro at 19% with
-tax not included:
-
-  my $invoice = invoice(invnumber => '144');
-  $invoice->amount
-  226.00000
-  $invoice->payment_terms->percent_skonto
-  0.02
-  $invoice->skonto_charts
-  pp $invoice->skonto_charts
-  #             $VAR1 = {
-  #               'chart_id'       => 128,
-  #               'skonto_amount'  => '2.14',
-  #               'skonto_percent' => '47.3451327433627'
-  #             };
-  #             $VAR2 = {
-  #               'chart_id'       => 130,
-  #               'skonto_amount'  => '2.38',
-  #               'skonto_percent' => '52.654867256637'
-  #             };
-
-C<skonto_charts> always returns positive values (abs) for C<skonto_amount> and
-C<skonto_percent>.
-
-C<skonto_charts> generates one entry for each acc_trans entry. ar and ap
-bookings only have one acc_trans entry for each taxkey (e.g. 7% and 19%).  This
-is because all the items are grouped according to the Buchungsgruppen mechanism
-and the totals are written to acc_trans.  For is and ir it is possible to have
-several acc_trans entries with the same tax. In this case skonto_charts
-generates a skonto booking for each acc_trans income/expense entry.
-
-In the future this function may also be used to calculate the corrections for
-the income tax.
+C<_skonto_charts_and_tax_correction> generates one entry for each tax type entry.
 
 =item C<open_amount>
 
@@ -1029,7 +1054,7 @@ Returns undef if skonto is not configured for that invoice.
 
 Creates data intended for an L.select_tag dropdown that can be used in a
 template. Depending on the rules it will choose from the options
-without_skonto, with_skonto_pt and difference_as_skonto, and select the most
+without_skonto and with_skonto_pt and select the most
 likely one.
 
 If the parameter "sepa" is passed, the SEPA export payments that haven't been
@@ -1043,8 +1068,6 @@ The current rules are:
 
 =item * with_skonto_pt is only offered if there haven't been any payments yet and the current date is within the skonto period.
 
-=item * difference_as_skonto is only offered if there have already been payments made and the open amount is smaller than 10% of the total amount.
-
 with_skonto_pt will only be offered, if all the AR_amount/AP_amount have a
 taxkey with a configured skonto chart
 
@@ -1091,7 +1114,7 @@ of a HTML drop-down select with the most likely option preselected.
 This is a helper function for BankTransaction/ajax_payment_suggestion and
 template/webpages/bank_transactions/invoices.html
 
-We are working with an existing payment, so difference_as_skonto never makes sense.
+We are working with an existing payment, so (deprecated) difference_as_skonto never makes sense.
 
 If skonto is not possible (skonto_date does not exists) simply return
 the single 'no skonto' option as a visual hint.
@@ -1124,7 +1147,7 @@ Returns 1 if record uses a different currency, 0 if the default currency is used
 when looking at open amount, maybe consider that there may already be queued
 amounts in SEPA Export
 
-=item * C<skonto_charts>
+=item * C<_skonto_charts_and_tax_correction>
 
 Cannot handle negative skonto amounts, will always calculate the skonto amount
 for credit notes or negative ap transactions with a positive sign.
diff --git a/SL/DB/Helper/SalesPurchaseInvoice.pm b/SL/DB/Helper/SalesPurchaseInvoice.pm
new file mode 100644 (file)
index 0000000..59e4697
--- /dev/null
@@ -0,0 +1,99 @@
+package SL::DB::Helper::SalesPurchaseInvoice;
+
+use strict;
+use utf8;
+
+use parent qw(Exporter);
+our @EXPORT = qw(get_tax_and_amount_by_tax_chart_id);
+
+sub get_tax_and_amount_by_tax_chart_id {
+  my ($self) = @_;
+
+  my $ARAP = $self->is_sales ? 'AR' : 'AP';
+  my ($tax_and_amount_by_tax_id, $total);
+
+  foreach my $transaction (@{ $self->transactions }) {
+    next if $transaction->chart_link =~ m/(^${ARAP}$|paid)/;
+
+    my $tax_or_netamount = $transaction->chart_link =~ m/tax/            ? 'tax'
+                         : $transaction->chart_link =~ m/(${ARAP}_amount|IC_cogs)/ ? 'netamount'
+                         : undef;
+    if ($tax_or_netamount eq 'netamount') {
+      $tax_and_amount_by_tax_id->{ $transaction->tax->chart_id }->{$tax_or_netamount} ||= 0;
+      $tax_and_amount_by_tax_id->{ $transaction->tax->chart_id }->{$tax_or_netamount}  += $transaction->amount;
+      # die "Invalid state" unless $tax_and_amount_by_tax_id->{ $transaction->tax->chart_id }->{tax_id} == 0
+      $tax_and_amount_by_tax_id->{ $transaction->tax->chart_id }->{tax_id}              = $transaction->tax_id;
+    } elsif ($tax_or_netamount eq 'tax') {
+      $tax_and_amount_by_tax_id->{ $transaction->chart_id }->{$tax_or_netamount} ||= 0;
+      $tax_and_amount_by_tax_id->{ $transaction->chart_id }->{$tax_or_netamount}  += $transaction->amount;
+    } else {
+      die "Invalid chart link at: " . $transaction->chart_link unless $tax_or_netamount;
+    }
+    $total ||= 0;
+    $total  += $transaction->amount;
+  }
+  die "Invalid calculated amount. Calc: $total Amount: " . abs($self->amount) if abs($total) - abs($self->amount) > 0.001;
+  return $tax_and_amount_by_tax_id;
+}
+
+
+
+1;
+
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::DB::Helper::SalesPurchaseInvoice - Helper functions for Sales or Purchase bookings (mirrored)
+
+Delivers the booked amounts split by net amount and tax amount for one ar or ap transaction
+as persisted in the table acc_trans.
+Should be rounding or calculation error prone because all values are already computed before
+the values are written in the acc_trans table.
+
+That is the main purpose for this helper class.
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<get_tax_and_amount_by_tax_chart_id>
+
+Iterates over all transactions for one distinct ar or ap transaction (trans_id in acc_trans) and
+groups the amounts in relation to distinct tax (tax.id) and net amounts (sums all bookings with
+_cogs or _amount chart links).
+Returns a hashref with the chart_id of the tax entry as key like this:
+
+ '775' => {
+    'tax_id'    => 777
+    'tax'       => '332.18',
+    'netamount' => '1748.32',
+  },
+
+ '194' => {
+    'tax_id'    => 378,
+    'netamount' => '20',
+    'tax'       => '1.4'
+  }
+
+C<tax_id> is the id of the used tax. C<tax> ist the amount of tax booked for the whole transaction.
+C<netamount> is the netamount booked with this tax.
+TODO: Please note the hash key chart_id may not be unique but the entry tax_id is always unique.
+
+As additional safety method the functions dies if the calculated sums do not match the
+the whole amount of the transaction with an accuracy of two decimal places.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Jan Büren E<lt>jan@kivitendo.deE<gt>
+
+=cut
index 5b45853..eb89ea8 100644 (file)
@@ -30,6 +30,8 @@ my %specs = ( ar                      => { number_column => 'invnumber',
               purchase_order          => { number_column => 'ordnumber',      number_range_column => 'ponumber',       scoping => \&oe_scoping,    },
               sales_delivery_order    => { number_column => 'donumber',       number_range_column => 'sdonumber',      scoping => \&do_scoping,    },
               purchase_delivery_order => { number_column => 'donumber',       number_range_column => 'pdonumber',      scoping => \&do_scoping,    },
+              supplier_delivery_order => { number_column => 'donumber',       number_range_column => 'sudonumber',     scoping => \&do_scoping,    },
+              rma_delivery_order      => { number_column => 'donumber',       number_range_column => 'rdonumber',      scoping => \&do_scoping,    },
               customer                => { number_column => 'customernumber', number_range_column => 'customernumber',                             },
               vendor                  => { number_column => 'vendornumber',   number_range_column => 'vendornumber',                               },
               part                    => { number_column => 'partnumber',     number_range_column => 'articlenumber',  scoping => \&parts_scoping, },
index a463db5..8557719 100644 (file)
@@ -4,15 +4,81 @@
 package SL::DB::Inventory;
 
 use strict;
+use Carp;
+use DateTime;
 
+use SL::DBUtils qw(selectrow_query);
 use SL::DB::MetaSetup::Inventory;
 use SL::DB::Manager::Inventory;
 
 __PACKAGE__->meta->initialize;
 
+__PACKAGE__->before_save(\&_before_save_create_trans_id);
+__PACKAGE__->before_save(\&_before_save_set_shippingdate);
+__PACKAGE__->before_save(\&_before_save_set_employee);
+
 # part accessor is badly named
 sub part {
   goto &parts;
 }
 
+sub new_from {
+  my ($class, $obj) = @_;
+
+  if ('SL::DB::DeliveryOrderItemsStock' eq ref $obj) {
+    return $class->new_from_delivery_order_stock($obj);
+  }
+
+  croak "unknown obj type (@{[ ref $obj ]}) for SL::DB::Inventory::new_from";
+}
+
+sub new_from_delivery_order_stock {
+  my ($class, $stock) = @_;
+
+  my $project = $stock->delivery_order_item->effective_project;
+
+  return $class->new(
+    delivery_order_items_stock_id => $stock->id,
+    parts_id                      => $stock->delivery_order_item->parts_id,
+    qty                           => $stock->unit_obj->convert_to($stock->qty => $stock->delivery_order_item->part->unit_obj),
+    warehouse_id                  => $stock->warehouse_id,
+    bin_id                        => $stock->bin_id,
+    chargenumber                  => $stock->chargenumber,
+    bestbefore                    => $stock->bestbefore,
+    project_id                    => $project ? $project->id : undef,
+    # trans_type - not set here, set in controller
+  );
+}
+
+sub _before_save_create_trans_id {
+  my ($self, %params) = @_;
+
+  return 1 if $self->trans_id;
+
+  my ($trans_id) = selectrow_query($::form, SL::DB->client->dbh, qq|SELECT nextval('id')|);
+
+  $self->trans_id($trans_id);
+
+  return 1;
+}
+
+sub _before_save_set_shippingdate {
+  my ($self, %params) = @_;
+
+  return 1 if $self->shippingdate;
+
+  $self->shippingdate(DateTime->now);
+
+  return 1;
+}
+
+sub _before_save_set_employee {
+  my ($self, %params) = @_;
+
+  return 1 if $self->employee_id;
+
+  $self->employee(SL::DB::Manager::Employee->current);
+
+  return 1;
+}
 1;
index 26faca1..d1ce5be 100644 (file)
@@ -16,6 +16,7 @@ use SL::DB::Helper::LinkedRecords;
 use SL::DB::Helper::PDF_A;
 use SL::DB::Helper::PriceTaxCalculator;
 use SL::DB::Helper::PriceUpdater;
+use SL::DB::Helper::SalesPurchaseInvoice;
 use SL::DB::Helper::TransNumberGenerator;
 use SL::DB::Helper::ZUGFeRD;
 use SL::Locale::String qw(t8);
@@ -173,7 +174,8 @@ sub new_from {
   $terms = $source->customer->payment_terms if !defined $terms && $source->customer;
 
   my %args = ( map({ ( $_ => $source->$_ ) } qw(customer_id taxincluded shippingpoint shipvia notes intnotes salesman_id cusordnumber ordnumber department_id
-                                                cp_id language_id taxzone_id tax_point globalproject_id transaction_description currency_id delivery_term_id), @columns),
+                                                cp_id language_id taxzone_id tax_point globalproject_id transaction_description currency_id delivery_term_id
+                                                billing_address_id), @columns),
                transdate   => $params{transdate} // DateTime->today_local,
                gldate      => DateTime->today_local,
                duedate     => $terms ? $terms->calc_date(reference_date => DateTime->today_local) : DateTime->today_local,
@@ -359,7 +361,6 @@ sub add_ar_amount_row {
     ($netamount, $taxamount) = Form->calculate_tax($params{amount}, $tax->rate, $self->taxincluded, $roundplaces);
   };
   next unless $netamount; # netamount mustn't be zero
-
   my $sign = $self->customer_id ? 1 : -1;
   my $acc = SL::DB::AccTransaction->new(
     amount     => $netamount * $sign,
@@ -425,7 +426,7 @@ sub create_ar_row {
   $self->add_transactions( $acc );
   push( @$acc_trans, $acc );
   return $acc_trans;
-};
+}
 
 sub validate_acc_trans {
   my ($self, %params) = @_;
@@ -538,7 +539,11 @@ sub invoice_type {
   my ($self) = @_;
 
   return 'ar_transaction'     if !$self->invoice;
-  return 'credit_note'        if $self->type eq 'credit_note' && $self->amount < 0 && !$self->storno;
+  return 'invoice_for_advance_payment_storno' if $self->type eq 'invoice_for_advance_payment' && $self->amount < 0 &&  $self->storno;
+  return 'invoice_for_advance_payment'        if $self->type eq 'invoice_for_advance_payment';
+  return 'final_invoice'                      if $self->type eq 'final_invoice';
+  # stornoed credit_notes are still credit notes and not invoices
+  return 'credit_note'        if $self->type eq 'credit_note' && $self->amount < 0;
   return 'invoice_storno'     if $self->type ne 'credit_note' && $self->amount < 0 &&  $self->storno;
   return 'credit_note_storno' if $self->type eq 'credit_note' && $self->amount > 0 &&  $self->storno;
   return 'invoice';
@@ -557,6 +562,9 @@ sub displayable_type {
   return t8('Credit Note')                            if $self->invoice_type eq 'credit_note';
   return t8('Invoice') . "(" . t8('Storno') . ")"     if $self->invoice_type eq 'invoice_storno';
   return t8('Credit Note') . "(" . t8('Storno') . ")" if $self->invoice_type eq 'credit_note_storno';
+  return t8('Invoice for Advance Payment')            if $self->invoice_type eq 'invoice_for_advance_payment';
+  return t8('Invoice for Advance Payment') . "(" . t8('Storno') . ")" if $self->invoice_type eq 'invoice_for_advance_payment_storno';
+  return t8('Final Invoice')                          if $self->invoice_type eq 'final_invoice';
   return t8('Invoice');
 }
 
@@ -571,6 +579,9 @@ sub abbreviation {
   return t8('Credit note (one letter abbreviation)') if $self->invoice_type eq 'credit_note';
   return t8('Invoice (one letter abbreviation)') . "(" . t8('Storno (one letter abbreviation)') . ")" if $self->invoice_type eq 'invoice_storno';
   return t8('Credit note (one letter abbreviation)') . "(" . t8('Storno (one letter abbreviation)') . ")"  if $self->invoice_type eq 'credit_note_storno';
+  return t8('Invoice for Advance Payment (one letter abbreviation)')  if $self->invoice_type eq 'invoice_for_advance_payment';
+  return t8('Invoice for Advance Payment with Storno (abbreviation)') if $self->invoice_type eq 'invoice_for_advance_payment_storno';
+  return t8('Final Invoice (one letter abbreviation)')                if $self->invoice_type eq 'final_invoice';
   return t8('Invoice (one letter abbreviation)');
 }
 
diff --git a/SL/DB/Manager/AdditionalBillingAddress.pm b/SL/DB/Manager/AdditionalBillingAddress.pm
new file mode 100644 (file)
index 0000000..297d534
--- /dev/null
@@ -0,0 +1,14 @@
+# This file has been auto-generated only because it didn't exist.
+# Feel free to modify it at will; it will not be overwritten automatically.
+
+package SL::DB::Manager::AdditionalBillingAddress;
+
+use strict;
+
+use parent qw(SL::DB::Helper::Manager);
+
+sub object_class { 'SL::DB::AdditionalBillingAddress' }
+
+__PACKAGE__->make_manager_methods;
+
+1;
diff --git a/SL/DB/Manager/ApGl.pm b/SL/DB/Manager/ApGl.pm
new file mode 100644 (file)
index 0000000..3cc0396
--- /dev/null
@@ -0,0 +1,14 @@
+# This file has been auto-generated only because it didn't exist.
+# Feel free to modify it at will; it will not be overwritten automatically.
+
+package SL::DB::Manager::ApGl;
+
+use strict;
+
+use parent qw(SL::DB::Helper::Manager);
+
+sub object_class { 'SL::DB::ApGl' }
+
+__PACKAGE__->make_manager_methods;
+
+1;
index 156ca7b..e9c1ee7 100644 (file)
@@ -8,6 +8,8 @@ use SL::DB::Helper::Paginated;
 use SL::DB::Helper::Sorted;
 use SL::DB::Helper::Filtered;
 
+use SL::DB::DeliveryOrder::TypeData qw(validate_type);
+
 sub object_class { 'SL::DB::DeliveryOrder' }
 
 __PACKAGE__->make_manager_methods;
@@ -26,11 +28,9 @@ __PACKAGE__->add_filter_specs(
 sub type_filter {
   my $class = shift;
   my $type  = lc(shift || '');
+  my $prefix = shift // '';
 
-  return ('!customer_id' => undef) if $type eq 'sales_delivery_order';
-  return ('!vendor_id'   => undef) if $type eq 'purchase_delivery_order';
-
-  die "Unknown type $type";
+  return "${prefix}order_type" => validate_type($type);
 }
 
 sub _sort_spec {
diff --git a/SL/DB/Manager/FileFullText.pm b/SL/DB/Manager/FileFullText.pm
new file mode 100644 (file)
index 0000000..bb1267d
--- /dev/null
@@ -0,0 +1,14 @@
+# This file has been auto-generated only because it didn't exist.
+# Feel free to modify it at will; it will not be overwritten automatically.
+
+package SL::DB::Manager::FileFullText;
+
+use strict;
+
+use parent qw(SL::DB::Helper::Manager);
+
+sub object_class { 'SL::DB::FileFullText' }
+
+__PACKAGE__->make_manager_methods;
+
+1;
diff --git a/SL/DB/MetaSetup/AdditionalBillingAddress.pm b/SL/DB/MetaSetup/AdditionalBillingAddress.pm
new file mode 100644 (file)
index 0000000..3e37db9
--- /dev/null
@@ -0,0 +1,43 @@
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::AdditionalBillingAddress;
+
+use strict;
+
+use parent qw(SL::DB::Object);
+
+__PACKAGE__->meta->table('additional_billing_addresses');
+
+__PACKAGE__->meta->columns(
+  city            => { type => 'text' },
+  contact         => { type => 'text' },
+  country         => { type => 'text' },
+  customer_id     => { type => 'integer' },
+  default_address => { type => 'boolean', default => 'false', not_null => 1 },
+  department_1    => { type => 'text' },
+  department_2    => { type => 'text' },
+  email           => { type => 'text' },
+  fax             => { type => 'text' },
+  gln             => { type => 'text' },
+  id              => { type => 'serial', not_null => 1 },
+  itime           => { type => 'timestamp', default => 'now()', not_null => 1 },
+  mtime           => { type => 'timestamp', default => 'now()', not_null => 1 },
+  name            => { type => 'text' },
+  phone           => { type => 'text' },
+  street          => { type => 'text' },
+  zipcode         => { type => 'text' },
+);
+
+__PACKAGE__->meta->primary_key_columns([ 'id' ]);
+
+__PACKAGE__->meta->allow_inline_column_values(1);
+
+__PACKAGE__->meta->foreign_keys(
+  customer => {
+    class       => 'SL::DB::Customer',
+    key_columns => { customer_id => 'id' },
+  },
+);
+
+1;
+;
diff --git a/SL/DB/MetaSetup/ApGl.pm b/SL/DB/MetaSetup/ApGl.pm
new file mode 100644 (file)
index 0000000..9f3f80a
--- /dev/null
@@ -0,0 +1,35 @@
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::ApGl;
+
+use strict;
+
+use parent qw(SL::DB::Object);
+
+__PACKAGE__->meta->table('ap_gl');
+
+__PACKAGE__->meta->columns(
+  ap_id => { type => 'integer', not_null => 1 },
+  gl_id => { type => 'integer', not_null => 1 },
+  itime => { type => 'timestamp', default => 'now()' },
+  mtime => { type => 'timestamp' },
+);
+
+__PACKAGE__->meta->primary_key_columns([ 'ap_id', 'gl_id' ]);
+
+__PACKAGE__->meta->allow_inline_column_values(1);
+
+__PACKAGE__->meta->foreign_keys(
+  ap => {
+    class       => 'SL::DB::PurchaseInvoice',
+    key_columns => { ap_id => 'id' },
+  },
+
+  gl => {
+    class       => 'SL::DB::GLTransaction',
+    key_columns => { gl_id => 'id' },
+  },
+);
+
+1;
+;
index 5589ee4..d836778 100644 (file)
@@ -11,6 +11,7 @@ __PACKAGE__->meta->table('bank_accounts');
 __PACKAGE__->meta->columns(
   account_number                  => { type => 'varchar', length => 100 },
   bank                            => { type => 'text' },
+  bank_account_id                 => { type => 'varchar' },
   bank_code                       => { type => 'varchar', length => 100 },
   bic                             => { type => 'varchar', length => 100 },
   chart_id                        => { type => 'integer', not_null => 1 },
@@ -21,6 +22,7 @@ __PACKAGE__->meta->columns(
   reconciliation_starting_balance => { type => 'numeric', precision => 15, scale => 5 },
   reconciliation_starting_date    => { type => 'date' },
   sortkey                         => { type => 'integer', not_null => 1 },
+  use_for_qrbill                  => { type => 'boolean', default => 'false', not_null => 1 },
   use_for_zugferd                 => { type => 'boolean', default => 'false', not_null => 1 },
 );
 
index b409191..295c6e7 100644 (file)
@@ -15,10 +15,14 @@ __PACKAGE__->meta->columns(
   address_street1                           => { type => 'text' },
   address_street2                           => { type => 'text' },
   address_zipcode                           => { type => 'text' },
+  advance_payment_clearing_chart_id         => { type => 'integer' },
+  advance_payment_taxable_19_id             => { type => 'integer' },
+  advance_payment_taxable_7_id              => { type => 'integer' },
   allow_new_purchase_delivery_order         => { type => 'boolean', default => 'true', not_null => 1 },
   allow_new_purchase_invoice                => { type => 'boolean', default => 'true', not_null => 1 },
   allow_sales_invoice_from_sales_order      => { type => 'boolean', default => 'true', not_null => 1 },
   allow_sales_invoice_from_sales_quotation  => { type => 'boolean', default => 'true', not_null => 1 },
+  always_record_links_from_order            => { type => 'boolean', default => 'false' },
   ap_add_doc                                => { type => 'boolean', default => 'false', not_null => 1 },
   ap_changeable                             => { type => 'integer', default => 2, not_null => 1 },
   ap_chart_id                               => { type => 'integer' },
@@ -45,6 +49,7 @@ __PACKAGE__->meta->columns(
   contact_departments_use_textfield         => { type => 'boolean' },
   contact_titles_use_textfield              => { type => 'boolean' },
   create_part_if_not_found                  => { type => 'boolean', default => 'false' },
+  create_qrbill_invoices                    => { type => 'integer' },
   create_zugferd_invoices                   => { type => 'integer' },
   currency_id                               => { type => 'integer', not_null => 1 },
   customer_hourly_rate                      => { type => 'numeric', precision => 8, scale => 2 },
@@ -105,6 +110,7 @@ __PACKAGE__->meta->columns(
   inventory_system                          => { type => 'text' },
   invnumber                                 => { type => 'text' },
   invoice_mail_settings                     => { type => 'enum', check_in => [ 'cp', 'invoice_mail', 'invoice_mail_cc_cp' ], db_type => 'invoice_mail_settings', default => 'cp' },
+  invoice_prevent_browser_back              => { type => 'boolean', default => 'false', not_null => 1 },
   ir_add_doc                                => { type => 'boolean', default => 'false', not_null => 1 },
   ir_changeable                             => { type => 'integer', default => 2, not_null => 1 },
   ir_show_mark_as_paid                      => { type => 'boolean', default => 'true' },
@@ -121,14 +127,17 @@ __PACKAGE__->meta->columns(
   normalize_vc_names                        => { type => 'boolean', default => 'true' },
   order_always_project                      => { type => 'boolean', default => 'false' },
   order_warn_duplicate_parts                => { type => 'boolean', default => 'true' },
+  order_warn_no_cusordnumber                => { type => 'boolean', default => 'false' },
   order_warn_no_deliverydate                => { type => 'boolean', default => 'true' },
   parts_image_css                           => { type => 'text', default => 'border:0;float:left;max-width:250px;margin-top:20px:margin-right:10px;margin-left:10px;' },
   parts_listing_image                       => { type => 'boolean', default => 'true' },
   parts_show_image                          => { type => 'boolean', default => 'true' },
+  partsgroup_required                       => { type => 'boolean', default => 'false', not_null => 1 },
   payments_changeable                       => { type => 'integer', default => '0', not_null => 1 },
   pdonumber                                 => { type => 'text' },
   ponumber                                  => { type => 'text' },
   precision                                 => { type => 'numeric', default => '0.01', not_null => 1, precision => 15, scale => 5 },
+  print_interpolate_variables_in_positions  => { type => 'boolean', default => 'true', not_null => 1 },
   produce_assembly_same_warehouse           => { type => 'boolean', default => 'true' },
   produce_assembly_transfer_service         => { type => 'boolean', default => 'false' },
   profit_carried_forward_chart_id           => { type => 'integer' },
@@ -140,6 +149,7 @@ __PACKAGE__->meta->columns(
   purchase_delivery_order_show_delete       => { type => 'boolean', default => 'true' },
   purchase_order_show_delete                => { type => 'boolean', default => 'true' },
   quick_search_modules                      => { type => 'array' },
+  rdonumber                                 => { type => 'text' },
   reqdate_interval                          => { type => 'integer', default => '0' },
   reqdate_on                                => { type => 'boolean', default => 'true' },
   require_transaction_description_ps        => { type => 'boolean', default => 'false', not_null => 1 },
@@ -154,6 +164,7 @@ __PACKAGE__->meta->columns(
   sales_delivery_order_show_delete          => { type => 'boolean', default => 'true' },
   sales_order_show_delete                   => { type => 'boolean', default => 'true' },
   sales_purchase_order_ship_missing_column  => { type => 'boolean', default => 'false' },
+  sales_purchase_record_numbers_changeable  => { type => 'boolean', default => 'false', not_null => 1 },
   sales_serial_eq_charge                    => { type => 'boolean', default => 'false', not_null => 1 },
   sdonumber                                 => { type => 'text' },
   sepa_creditor_id                          => { type => 'text' },
@@ -173,6 +184,7 @@ __PACKAGE__->meta->columns(
   stocktaking_cutoff_date                   => { type => 'date' },
   stocktaking_qty_threshold                 => { type => 'numeric', default => '0', precision => 25, scale => 5 },
   stocktaking_warehouse_id                  => { type => 'integer' },
+  sudonumber                                => { type => 'text' },
   taxnumber                                 => { type => 'text' },
   templates                                 => { type => 'text' },
   transfer_default                          => { type => 'boolean', default => 'true' },
@@ -188,6 +200,7 @@ __PACKAGE__->meta->columns(
   vertreter                                 => { type => 'boolean', default => 'false' },
   warehouse_id                              => { type => 'integer' },
   warehouse_id_ignore_onhand                => { type => 'integer' },
+  warn_no_delivery_order_for_invoice        => { type => 'boolean', default => 'false' },
   webdav                                    => { type => 'boolean', default => 'false' },
   webdav_documents                          => { type => 'boolean', default => 'false' },
   weightunit                                => { type => 'varchar', length => 5 },
index 780f431..994fa96 100644 (file)
@@ -9,6 +9,7 @@ use parent qw(SL::DB::Object);
 __PACKAGE__->meta->table('delivery_orders');
 
 __PACKAGE__->meta->columns(
+  billing_address_id      => { type => 'integer' },
   closed                  => { type => 'boolean', default => 'false' },
   cp_id                   => { type => 'integer' },
   currency_id             => { type => 'integer', not_null => 1 },
@@ -22,11 +23,11 @@ __PACKAGE__->meta->columns(
   globalproject_id        => { type => 'integer' },
   id                      => { type => 'integer', not_null => 1, sequence => 'id' },
   intnotes                => { type => 'text' },
-  is_sales                => { type => 'boolean' },
   itime                   => { type => 'timestamp', default => 'now()' },
   language_id             => { type => 'integer' },
   mtime                   => { type => 'timestamp' },
   notes                   => { type => 'text' },
+  order_type              => { type => 'text', not_null => 1 },
   ordnumber               => { type => 'text' },
   oreqnumber              => { type => 'text' },
   payment_id              => { type => 'integer' },
@@ -48,6 +49,11 @@ __PACKAGE__->meta->primary_key_columns([ 'id' ]);
 __PACKAGE__->meta->allow_inline_column_values(1);
 
 __PACKAGE__->meta->foreign_keys(
+  billing_address => {
+    class       => 'SL::DB::AdditionalBillingAddress',
+    key_columns => { billing_address_id => 'id' },
+  },
+
   contact => {
     class       => 'SL::DB::Contact',
     key_columns => { cp_id => 'cp_id' },
index 257e09f..e5fd622 100644 (file)
@@ -9,19 +9,20 @@ use parent qw(SL::DB::Object);
 __PACKAGE__->meta->table('files');
 
 __PACKAGE__->meta->columns(
-  backend      => { type => 'text' },
-  backend_data => { type => 'text' },
-  description  => { type => 'text' },
-  file_name    => { type => 'text', not_null => 1 },
-  file_type    => { type => 'text', not_null => 1 },
-  id           => { type => 'serial', not_null => 1 },
-  itime        => { type => 'timestamp', default => 'now()' },
-  mime_type    => { type => 'text', not_null => 1 },
-  mtime        => { type => 'timestamp' },
-  object_id    => { type => 'integer', not_null => 1 },
-  object_type  => { type => 'text', not_null => 1 },
-  source       => { type => 'text', not_null => 1 },
-  title        => { type => 'varchar', length => 45 },
+  backend       => { type => 'text' },
+  backend_data  => { type => 'text' },
+  description   => { type => 'text' },
+  file_name     => { type => 'text', not_null => 1 },
+  file_type     => { type => 'text', not_null => 1 },
+  id            => { type => 'serial', not_null => 1 },
+  itime         => { type => 'timestamp', default => 'now()' },
+  mime_type     => { type => 'text', not_null => 1 },
+  mtime         => { type => 'timestamp' },
+  object_id     => { type => 'integer', not_null => 1 },
+  object_type   => { type => 'text', not_null => 1 },
+  print_variant => { type => 'text' },
+  source        => { type => 'text', not_null => 1 },
+  title         => { type => 'varchar', length => 45 },
 );
 
 __PACKAGE__->meta->primary_key_columns([ 'id' ]);
diff --git a/SL/DB/MetaSetup/FileFullText.pm b/SL/DB/MetaSetup/FileFullText.pm
new file mode 100644 (file)
index 0000000..2a93822
--- /dev/null
@@ -0,0 +1,31 @@
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::FileFullText;
+
+use strict;
+
+use parent qw(SL::DB::Object);
+
+__PACKAGE__->meta->table('file_full_texts');
+
+__PACKAGE__->meta->columns(
+  file_id   => { type => 'integer', not_null => 1 },
+  full_text => { type => 'text', not_null => 1 },
+  id        => { type => 'serial', not_null => 1 },
+  itime     => { type => 'timestamp', default => 'now()', not_null => 1 },
+  mtime     => { type => 'timestamp' },
+);
+
+__PACKAGE__->meta->primary_key_columns([ 'id' ]);
+
+__PACKAGE__->meta->allow_inline_column_values(1);
+
+__PACKAGE__->meta->foreign_keys(
+  file => {
+    class       => 'SL::DB::File',
+    key_columns => { file_id => 'id' },
+  },
+);
+
+1;
+;
index 80c7e85..a2cda63 100644 (file)
@@ -9,25 +9,26 @@ use parent qw(SL::DB::Object);
 __PACKAGE__->meta->table('gl');
 
 __PACKAGE__->meta->columns(
-  cb_transaction => { type => 'boolean' },
-  deliverydate   => { type => 'date' },
-  department_id  => { type => 'integer' },
-  description    => { type => 'text' },
-  employee_id    => { type => 'integer' },
-  gldate         => { type => 'date', default => 'now' },
-  id             => { type => 'integer', not_null => 1, sequence => 'glid' },
-  imported       => { type => 'boolean', default => 'false' },
-  itime          => { type => 'timestamp', default => 'now()' },
-  mtime          => { type => 'timestamp' },
-  notes          => { type => 'text' },
-  ob_transaction => { type => 'boolean' },
-  reference      => { type => 'text' },
-  storno         => { type => 'boolean', default => 'false' },
-  storno_id      => { type => 'integer' },
-  tax_point      => { type => 'date' },
-  taxincluded    => { type => 'boolean' },
-  transdate      => { type => 'date', default => 'now' },
-  type           => { type => 'text' },
+  cb_transaction          => { type => 'boolean' },
+  deliverydate            => { type => 'date' },
+  department_id           => { type => 'integer' },
+  description             => { type => 'text' },
+  employee_id             => { type => 'integer' },
+  gldate                  => { type => 'date', default => 'now' },
+  id                      => { type => 'integer', not_null => 1, sequence => 'glid' },
+  imported                => { type => 'boolean', default => 'false' },
+  itime                   => { type => 'timestamp', default => 'now()' },
+  mtime                   => { type => 'timestamp' },
+  notes                   => { type => 'text' },
+  ob_transaction          => { type => 'boolean' },
+  reference               => { type => 'text' },
+  storno                  => { type => 'boolean', default => 'false' },
+  storno_id               => { type => 'integer' },
+  tax_point               => { type => 'date' },
+  taxincluded             => { type => 'boolean' },
+  transaction_description => { type => 'text' },
+  transdate               => { type => 'date', default => 'now' },
+  type                    => { type => 'text' },
 );
 
 __PACKAGE__->meta->primary_key_columns([ 'id' ]);
index 9b10c93..e80b110 100644 (file)
@@ -10,6 +10,7 @@ __PACKAGE__->meta->table('ar');
 
 __PACKAGE__->meta->columns(
   amount                    => { type => 'numeric', default => '0', not_null => 1, precision => 15, scale => 5 },
+  billing_address_id        => { type => 'integer' },
   cp_id                     => { type => 'integer' },
   currency_id               => { type => 'integer', not_null => 1 },
   cusordnumber              => { type => 'text' },
@@ -43,6 +44,7 @@ __PACKAGE__->meta->columns(
   ordnumber                 => { type => 'text' },
   paid                      => { type => 'numeric', default => '0', not_null => 1, precision => 15, scale => 5 },
   payment_id                => { type => 'integer' },
+  qrbill_without_amount     => { type => 'boolean', default => 'false' },
   quodate                   => { type => 'date' },
   quonumber                 => { type => 'text' },
   salesman_id               => { type => 'integer' },
@@ -64,6 +66,11 @@ __PACKAGE__->meta->primary_key_columns([ 'id' ]);
 __PACKAGE__->meta->allow_inline_column_values(1);
 
 __PACKAGE__->meta->foreign_keys(
+  billing_address => {
+    class       => 'SL::DB::AdditionalBillingAddress',
+    key_columns => { billing_address_id => 'id' },
+  },
+
   contact => {
     class       => 'SL::DB::Contact',
     key_columns => { cp_id => 'cp_id' },
index 85b8876..8a67022 100644 (file)
@@ -35,7 +35,7 @@ __PACKAGE__->meta->columns(
   price_factor_id        => { type => 'integer' },
   pricegroup_id          => { type => 'integer' },
   project_id             => { type => 'integer' },
-  qty                    => { type => 'float', precision => 4, scale => 4 },
+  qty                    => { type => 'numeric', precision => 25, scale => 5 },
   sellprice              => { type => 'numeric', precision => 15, scale => 5 },
   serialnumber           => { type => 'text' },
   subtotal               => { type => 'boolean', default => 'false' },
index 9aa8039..96d0a0a 100644 (file)
@@ -14,6 +14,7 @@ __PACKAGE__->meta->columns(
   id                  => { type => 'integer', not_null => 1, sequence => 'id' },
   itime               => { type => 'timestamp', default => 'now()' },
   mtime               => { type => 'timestamp' },
+  obsolete            => { type => 'boolean', default => 'false' },
   output_dateformat   => { type => 'text' },
   output_longdates    => { type => 'boolean' },
   output_numberformat => { type => 'text' },
index 6e707ae..5dda642 100644 (file)
@@ -10,6 +10,7 @@ __PACKAGE__->meta->table('oe');
 
 __PACKAGE__->meta->columns(
   amount                  => { type => 'numeric', precision => 15, scale => 5 },
+  billing_address_id      => { type => 'integer' },
   closed                  => { type => 'boolean', default => 'false' },
   cp_id                   => { type => 'integer' },
   currency_id             => { type => 'integer', not_null => 1 },
@@ -57,6 +58,11 @@ __PACKAGE__->meta->primary_key_columns([ 'id' ]);
 __PACKAGE__->meta->allow_inline_column_values(1);
 
 __PACKAGE__->meta->foreign_keys(
+  billing_address => {
+    class       => 'SL::DB::AdditionalBillingAddress',
+    key_columns => { billing_address_id => 'id' },
+  },
+
   contact => {
     class       => 'SL::DB::Contact',
     key_columns => { cp_id => 'cp_id' },
index afa64d8..e83b65b 100644 (file)
@@ -31,7 +31,7 @@ __PACKAGE__->meta->columns(
   price_factor_id        => { type => 'integer' },
   pricegroup_id          => { type => 'integer' },
   project_id             => { type => 'integer' },
-  qty                    => { type => 'float', precision => 4, scale => 4 },
+  qty                    => { type => 'numeric', precision => 25, scale => 5 },
   reqdate                => { type => 'date' },
   sellprice              => { type => 'numeric', precision => 15, scale => 5 },
   serialnumber           => { type => 'text' },
index 83850ff..374f00c 100644 (file)
@@ -9,28 +9,29 @@ use parent qw(SL::DB::Object);
 __PACKAGE__->meta->table('record_templates');
 
 __PACKAGE__->meta->columns(
-  ar_ap_chart_id => { type => 'integer' },
-  cb_transaction => { type => 'boolean', default => 'false', not_null => 1 },
-  currency_id    => { type => 'integer', not_null => 1 },
-  customer_id    => { type => 'integer' },
-  department_id  => { type => 'integer' },
-  description    => { type => 'text' },
-  direct_debit   => { type => 'boolean', default => 'false', not_null => 1 },
-  employee_id    => { type => 'integer' },
-  id             => { type => 'serial', not_null => 1 },
-  itime          => { type => 'timestamp', default => 'now()', not_null => 1 },
-  mtime          => { type => 'timestamp', default => 'now()', not_null => 1 },
-  notes          => { type => 'text' },
-  ob_transaction => { type => 'boolean', default => 'false', not_null => 1 },
-  ordnumber      => { type => 'text' },
-  payment_id     => { type => 'integer' },
-  project_id     => { type => 'integer' },
-  reference      => { type => 'text' },
-  show_details   => { type => 'boolean', default => 'false', not_null => 1 },
-  taxincluded    => { type => 'boolean', default => 'false', not_null => 1 },
-  template_name  => { type => 'text', not_null => 1 },
-  template_type  => { type => 'enum', check_in => [ 'ar_transaction', 'ap_transaction', 'gl_transaction' ], db_type => 'record_template_type', not_null => 1 },
-  vendor_id      => { type => 'integer' },
+  ar_ap_chart_id          => { type => 'integer' },
+  cb_transaction          => { type => 'boolean', default => 'false', not_null => 1 },
+  currency_id             => { type => 'integer', not_null => 1 },
+  customer_id             => { type => 'integer' },
+  department_id           => { type => 'integer' },
+  description             => { type => 'text' },
+  direct_debit            => { type => 'boolean', default => 'false', not_null => 1 },
+  employee_id             => { type => 'integer' },
+  id                      => { type => 'serial', not_null => 1 },
+  itime                   => { type => 'timestamp', default => 'now()', not_null => 1 },
+  mtime                   => { type => 'timestamp', default => 'now()', not_null => 1 },
+  notes                   => { type => 'text' },
+  ob_transaction          => { type => 'boolean', default => 'false', not_null => 1 },
+  ordnumber               => { type => 'text' },
+  payment_id              => { type => 'integer' },
+  project_id              => { type => 'integer' },
+  reference               => { type => 'text' },
+  show_details            => { type => 'boolean', default => 'false', not_null => 1 },
+  taxincluded             => { type => 'boolean', default => 'false', not_null => 1 },
+  template_name           => { type => 'text', not_null => 1 },
+  template_type           => { type => 'enum', check_in => [ 'ar_transaction', 'ap_transaction', 'gl_transaction' ], db_type => 'record_template_type', not_null => 1 },
+  transaction_description => { type => 'text' },
+  vendor_id               => { type => 'integer' },
 );
 
 __PACKAGE__->meta->primary_key_columns([ 'id' ]);
index 1110fd0..adb6b3a 100644 (file)
@@ -9,27 +9,29 @@ use parent qw(SL::DB::Object);
 __PACKAGE__->meta->table('shops');
 
 __PACKAGE__->meta->columns(
-  connector               => { type => 'text' },
-  description             => { type => 'text' },
-  id                      => { type => 'serial', not_null => 1 },
-  itime                   => { type => 'timestamp', default => 'now()' },
-  last_order_number       => { type => 'integer' },
-  login                   => { type => 'text' },
-  mtime                   => { type => 'timestamp', default => 'now()' },
-  obsolete                => { type => 'boolean', default => 'false', not_null => 1 },
-  orders_to_fetch         => { type => 'integer' },
-  password                => { type => 'text' },
-  path                    => { type => 'text', default => '/', not_null => 1 },
-  port                    => { type => 'integer' },
-  price_source            => { type => 'text' },
-  pricetype               => { type => 'text' },
-  protocol                => { type => 'text', default => 'http', not_null => 1 },
-  realm                   => { type => 'text' },
-  server                  => { type => 'text' },
-  shipping_costs_parts_id => { type => 'integer' },
-  sortkey                 => { type => 'integer' },
-  taxzone_id              => { type => 'integer' },
-  transaction_description => { type => 'text' },
+  connector                => { type => 'text' },
+  description              => { type => 'text' },
+  id                       => { type => 'serial', not_null => 1 },
+  itime                    => { type => 'timestamp', default => 'now()' },
+  last_order_number        => { type => 'integer' },
+  login                    => { type => 'text' },
+  mtime                    => { type => 'timestamp', default => 'now()' },
+  obsolete                 => { type => 'boolean', default => 'false', not_null => 1 },
+  orders_to_fetch          => { type => 'integer' },
+  password                 => { type => 'text' },
+  path                     => { type => 'text', default => '/', not_null => 1 },
+  port                     => { type => 'integer' },
+  price_source             => { type => 'text' },
+  pricetype                => { type => 'text' },
+  protocol                 => { type => 'text', default => 'http', not_null => 1 },
+  proxy                    => { type => 'text', default => '' },
+  realm                    => { type => 'text' },
+  server                   => { type => 'text' },
+  shipping_costs_parts_id  => { type => 'integer' },
+  sortkey                  => { type => 'integer' },
+  taxzone_id               => { type => 'integer' },
+  transaction_description  => { type => 'text' },
+  use_part_longdescription => { type => 'boolean', default => 'false' },
 );
 
 __PACKAGE__->meta->primary_key_columns([ 'id' ]);
index cd31c18..6b685fa 100644 (file)
@@ -77,7 +77,7 @@ __PACKAGE__->meta->columns(
   shop_customer_number   => { type => 'text' },
   shop_id                => { type => 'integer' },
   shop_ordernumber       => { type => 'text' },
-  shop_trans_id          => { type => 'integer', not_null => 1 },
+  shop_trans_id          => { type => 'text', not_null => 1 },
   tax_included           => { type => 'boolean' },
   transfer_date          => { type => 'date' },
   transferred            => { type => 'boolean', default => 'false' },
index dfb2255..ae7d21a 100644 (file)
@@ -17,7 +17,7 @@ __PACKAGE__->meta->columns(
   price               => { type => 'numeric', precision => 15, scale => 5 },
   quantity            => { type => 'numeric', precision => 25, scale => 5 },
   shop_order_id       => { type => 'integer' },
-  shop_trans_id       => { type => 'integer', not_null => 1 },
+  shop_trans_id       => { type => 'text', not_null => 1 },
   tax_rate            => { type => 'numeric', precision => 15, scale => 2 },
 );
 
index 55aba86..c29a455 100644 (file)
@@ -15,6 +15,7 @@ __PACKAGE__->meta->columns(
   itime                    => { type => 'timestamp', default => 'now()' },
   mtime                    => { type => 'timestamp' },
   rate                     => { type => 'numeric', default => '0', not_null => 1, precision => 15, scale => 5 },
+  reverse_charge_chart_id  => { type => 'integer' },
   skonto_purchase_chart_id => { type => 'integer' },
   skonto_sales_chart_id    => { type => 'integer' },
   taxdescription           => { type => 'text', not_null => 1 },
index fe0b321..fdaa1e8 100644 (file)
@@ -47,6 +47,16 @@ __PACKAGE__->meta->add_relationship(
     class                  => 'SL::DB::Exchangerate',
     column_map             => { currency_id => 'currency_id', transdate => 'transdate' },
   },
+  phone_notes => {
+    type         => 'one to many',
+    class        => 'SL::DB::Note',
+    column_map   => { id => 'trans_id' },
+    query_args   => [ trans_module => 'oe' ],
+    manager_args => {
+      with_objects => [ 'employee' ],
+      sort_by      => 'notes.itime',
+    }
+  },
 );
 
 SL::DB::Helper::Attr::make(__PACKAGE__, daily_exchangerate => 'numeric');
@@ -238,8 +248,23 @@ sub convert_to_invoice {
   my $invoice;
   if (!$self->db->with_transaction(sub {
     require SL::DB::Invoice;
-    $invoice = SL::DB::Invoice->new_from($self)->post(%params) || die;
+    $invoice = SL::DB::Invoice->new_from($self, %params)->post || die;
     $self->link_to_record($invoice);
+    # TODO extend link_to_record for items, otherwise long-term no d.r.y.
+    foreach my $item (@{ $invoice->items }) {
+      foreach (qw(orderitems)) {
+        if ($item->{"converted_from_${_}_id"}) {
+          die unless $item->{id};
+          RecordLinks->create_links('mode'       => 'ids',
+                                    'from_table' => $_,
+                                    'from_ids'   => $item->{"converted_from_${_}_id"},
+                                    'to_table'   => 'invoice',
+                                    'to_id'      => $item->{id},
+          ) || die;
+          delete $item->{"converted_from_${_}_id"};
+        }
+      }
+    }
     $self->update_attributes(closed => 1);
     1;
   })) {
@@ -328,21 +353,21 @@ sub new_from {
   }
 
   my %args = ( map({ ( $_ => $source->$_ ) } qw(amount cp_id currency_id cusordnumber customer_id delivery_customer_id delivery_term_id delivery_vendor_id
-                                                department_id employee_id exchangerate globalproject_id intnotes marge_percent marge_total language_id netamount notes
+                                                department_id exchangerate globalproject_id intnotes marge_percent marge_total language_id netamount notes
                                                 ordnumber payment_id quonumber reqdate salesman_id shippingpoint shipvia taxincluded tax_point taxzone_id
-                                                transaction_description vendor_id
+                                                transaction_description vendor_id billing_address_id
                                              )),
                quotation => !!($destination_type =~ m{quotation$}),
                closed    => 0,
                delivered => 0,
                transdate => DateTime->today_local,
+               employee  => SL::DB::Manager::Employee->current,
             );
 
   if ( $is_abbr_any->(qw(sopo poso)) ) {
     $args{ordnumber} = undef;
     $args{quonumber} = undef;
     $args{reqdate}   = DateTime->today_local->next_workday();
-    $args{employee}  = SL::DB::Manager::Employee->current;
   }
   if ( $is_abbr_any->(qw(sopo)) ) {
     $args{customer_id}      = undef;
@@ -448,7 +473,7 @@ sub new_from_multi {
                        order_probability expected_billing_date)) {
     $attributes{$attr} = undef if any { ($sources->[0]->$attr//'') ne ($_->$attr//'') } @$sources;
   }
-  foreach my $attr (qw(cp_id currency_id employee_id salesman_id department_id
+  foreach my $attr (qw(cp_id currency_id salesman_id department_id
                        delivery_customer_id delivery_vendor_id shipto_id
                        globalproject_id exchangerate)) {
     $attributes{$attr} = undef if any { ($sources->[0]->$attr||0) != ($_->$attr||0) }   @$sources;
@@ -463,6 +488,9 @@ sub new_from_multi {
   # no periodic invoice config for new order
   $attributes{periodic_invoices_config} = undef;
 
+  # set emplyee to the current one
+  $attributes{employee} = SL::DB::Manager::Employee->current;
+
   # copy global ordnumber, transdate, cusordnumber into item scope
   #   unless already present there
   foreach my $attr (qw(ordnumber transdate cusordnumber)) {
@@ -598,7 +626,7 @@ L<SL::DB::Invoice::new_from>. That invoice is posted, and C<$self> is
 linked to the new invoice via L<SL::DB::RecordLink>. C<$self>'s
 C<closed> attribute is set to C<true>, and C<$self> is saved.
 
-The arguments in C<%params> are passed to L<SL::DB::Invoice::post>.
+The arguments in C<%params> are passed to L<SL::DB::Invoice::new_from>.
 
 Returns the new invoice instance on success and C<undef> on
 failure. The whole process is run inside a transaction. On failure
index 1ee4f26..89261af 100644 (file)
@@ -139,6 +139,13 @@ sub validate {
   push @errors, $::locale->text('The unit is missing.')           unless $self->unit;
   push @errors, $::locale->text('The buchungsgruppe is missing.') unless $self->buchungsgruppen_id or $self->buchungsgruppe;
 
+  if ( $::instance_conf->get_partsgroup_required
+       && ( !$self->partsgroup_id or ( $self->id && !$self->partsgroup_id && $self->partsgroup ) ) ) {
+    # when unsetting an existing partsgroup in the interface, $self->partsgroup_id will be undef but $self->partsgroup will still have a value
+    # this needs to be checked, as partsgroup dropdown has an empty value
+    push @errors, $::locale->text('The partsgroup is missing.');
+  }
+
   unless ( $self->id ) {
     push @errors, $::locale->text('The partnumber already exists.') if SL::DB::Manager::Part->get_all_count(where => [ partnumber => $self->partnumber ]);
   };
index db443e9..2f62bd9 100644 (file)
@@ -35,7 +35,7 @@ sub calc_date {
   }
 
   my $terms           = ($params{terms} // 'net') eq 'discount' ? 'terms_skonto' : 'terms_netto';
-  my $date            = $reference_date->add(days => $self->$terms);
+  my $date            = $reference_date->clone->add(days => $self->$terms);
 
   my $dow             = $date->day_of_week;
   $date               = $date->add(days => 8 - $dow) if $dow > 5;
index eee044f..a7cfc20 100644 (file)
@@ -7,6 +7,7 @@ use SL::DB::Manager::Pricegroup;
 use SL::DB::Helper::ActsAsList;
 
 __PACKAGE__->meta->initialize;
+__PACKAGE__->before_save('_before_save_remove_customer_pricegroup');
 
 sub displayable_name {
   my $self = shift;
@@ -14,14 +15,32 @@ sub displayable_name {
   return join ' ', grep $_, $self->id, $self->pricegroup;
 }
 
+sub _before_save_remove_customer_pricegroup {
+  my ($self) = @_;
+
+  return 1 unless $::form->{SELF}{remove_customer_pricegroup};
+
+  my %attributes          = (pricegroup_id => undef);
+  require SL::DB::Customer;
+  SL::DB::Manager::Customer->update_all(
+    set   => \%attributes,
+    where => [
+      'pricegroup_id' => $self->id,
+    ],
+  );
+
+  return 1;
+}
+
 sub validate {
   my ($self) = @_;
   require SL::DB::Customer;
 
   my @errors;
-
-  if ( $self->obsolete && SL::DB::Manager::Customer->get_all_count(query => [ pricegroup_id => $self->id ]) ) {
-    push @errors, $::locale->text('The pricegroup is being used by customers.');
+  if (!$::form->{SELF}{remove_customer_pricegroup}                                    &&
+      $self->obsolete                                                                 &&
+      SL::DB::Manager::Customer->get_all_count(query => [ pricegroup_id => $self->id ]) ) {
+      push @errors, $::locale->text('The pricegroup is being used by customers.');
   }
 
   return @errors;
index dd49433..3eb320e 100644 (file)
@@ -11,6 +11,7 @@ use SL::DB::Helper::AttrHTML;
 use SL::DB::Helper::AttrSorted;
 use SL::DB::Helper::LinkedRecords;
 use SL::DB::Helper::Payment qw(:ALL);
+use SL::DB::Helper::SalesPurchaseInvoice;
 use SL::Locale::String qw(t8);
 use Rose::DB::Object::Helpers qw(has_loaded_related forget_related);
 
index 63f988f..bcae321 100644 (file)
@@ -16,10 +16,26 @@ sub validate {
   my ($self) = @_;
 
   my @errors;
-
+  # critical checks
   push @errors, $::locale->text('The description is missing.') unless $self->{description};
-  push @errors, $::locale->text('The path is missing.') unless $self->{path};
-
+  push @errors, $::locale->text('The path is missing.')        unless $self->{path};
+  push @errors, $::locale->text('The Host Name is missing')    unless $self->{server};
+  push @errors, $::locale->text('The Host Name seems invalid') unless $self->{server} =~ m/[0-9A-Za-z].\.[0-9A-Za-z]/;
+  push @errors, $::locale->text('The Protocol for Host Name seems invalid (expected: http:// or https://)!')
+                                                               if ($self->{server} =~ m/:/ && $self->{server} !~ m/(^https:\/\/|^http:\/\/)/);
+  push @errors, $::locale->text('The Proxy Name seems invalid') . $self->{proxy} . ':' unless !$self->{proxy} ||  $self->{proxy} =~ m/[0-9A-Za-z].\.[0-9A-Za-z]/;
+  push @errors, $::locale->text('Orders to fetch neeeds a positive Integer')
+                                                               unless $self->{orders_to_fetch} > 0;
+
+  # not yet implemented checks
+  if ($self->{connector} eq 'shopware6') {
+    push @errors, $::locale->text('Transaction Description is not yet implemented')  if $self->{transaction_description};
+    push @errors, $::locale->text('Shipping cost article is not implemented')        if $self->{shipping_costs_parts_id};
+    push @errors, $::locale->text('Fetch from last order number is not implemented') if $self->{last_order_number};
+  } else {
+    push @errors, $::locale->text('Use Long Description from Parts is only for Shopware6 implemented')
+      if $self->{use_part_longdescription};
+  }
   return @errors;
 }
 
index ae5d856..6a53387 100644 (file)
@@ -48,7 +48,8 @@ sub convert_to_sales_order {
     }else{
       my $current_order_item = SL::DB::OrderItem->new(
         parts_id            => $part->id,
-        description         => $part->description,
+        description         => $_->description, # description from the shop
+        longdescription     => $part->notes,    # longdescription from parts. TODO locales
         qty                 => $_->quantity,
         sellprice           => $_->price,
         unit                => $part->unit,
@@ -137,11 +138,11 @@ WHERE (
  OR
    ( street % ?  AND zipcode ILIKE ?)
  OR
-   email ILIKE ?
+   ( email ILIKE ? OR invoice_mail ILIKE ? )
 ) AND obsolete = 'F'
 SQL
 
-    my @values = ($lastname, $company, $self->billing_zipcode, $street, $self->billing_zipcode, $self->billing_email);
+    my @values = ($lastname, $company, $self->billing_zipcode, $street, $self->billing_zipcode, $self->billing_email, $self->billing_email);
 
     $customers = SL::DB::Manager::Customer->get_objects_from_sql(
       sql  => $fs_query,
@@ -151,20 +152,24 @@ SQL
     # If trgm extension is not installed
     $customers = SL::DB::Manager::Customer->get_all(
       where => [
-          or => [
-            and => [
-                     or => [ 'name' => { ilike => $lastname },
-                             'name' => { ilike => $company  },
-                           ],
-                     'zipcode' => { ilike => $zipcode },
+                 or => [
+                   and => [
+                            or => [ 'name' => { ilike => $lastname },
+                                    'name' => { ilike => $company  },
+                            ],
+                            'zipcode' => { ilike => $zipcode },
                    ],
-            and => [
-                     and => [ 'street'  => { ilike => $street_not_fuzzy },
-                              'zipcode' => { ilike => $zipcode },
+                   and => [
+                            and => [ 'street'  => { ilike => $street_not_fuzzy },
+                                     'zipcode' => { ilike => $zipcode },
                             ],
                    ],
-            or  => [ 'email' => { ilike => $email } ],
-          ],
+                   or  => [
+                            'email'        => { ilike => $email },
+                            'invoice_mail' => { ilike => $email },
+                   ],
+                 ],
+                 and => [ obsolete => 'F' ]
       ],
     );
   }
@@ -198,6 +203,7 @@ sub get_customer{
                     'zipcode'               => $self->billing_zipcode,
                     'city'                  => $self->billing_city,
                     'email'                 => $self->billing_email,
+                    'invoice_mail'          => $self->billing_email,
                     'country'               => $self->billing_country,
                     'greeting'              => $self->billing_greeting,
                     'fax'                   => $self->billing_fax,
@@ -233,6 +239,7 @@ sub get_customer{
                                                     obsolete => 'F',
                                                   );
   }
+  $customer->update_attributes(invoice_mail => $self->billing_email) if $customer->invoice_mail ne $self->billing_email;
 
   return $customer;
 }
index 1df77fd..7c67bb1 100644 (file)
@@ -50,16 +50,20 @@ sub get_tax_and_price {
 }
 
 sub get_images {
-  my ( $self ) = @_;
+  my ($self, %params) = @_;
 
   require SL::DB::ShopImage;
   my $images = SL::DB::Manager::ShopImage->get_all( where => [ 'files.object_id' => $self->{part_id}, ], with_objects => 'file', sort_by => 'position' );
   my @upload_img = ();
   foreach my $img (@{ $images }) {
     my $file               = SL::File->get(id => $img->file->id );
-    my ($path, $extension) = (split /\./, $file->file_name);
+    # no good: split("\." , 202.220.pdf) -> invaild extension 220
+    # file->extension should be in SL::File, a valid extension may also be 'tar.gz'
+    my ($path, $extension) = split(/\.([^\.]+)$/, $file->file_name);
     my $content            = File::Slurp::read_file($file->get_file);
-    my $temp ={ ( link        => 'data:' . $file->mime_type . ';base64,' . MIME::Base64::encode($content, ""), #$content, # MIME::Base64::encode($content),
+
+    my $temp ={ (
+                  link        => $params{want_binary} ? $content : 'data:' . $file->mime_type . ';base64,' . MIME::Base64::encode($content, ""),
                   description => $img->file->title,
                   position    => $img->position,
                   extension   => $extension,
index c41f287..3cc7490 100644 (file)
@@ -2,11 +2,13 @@ package SL::DB::VC;
 
 use strict;
 
-require Exporter;
+use List::MoreUtils qw(uniq);
 use SL::DBUtils;
 
+require Exporter;
+
 our @ISA    = qw(Exporter);
-our @EXPORT = qw(get_credit_remaining);
+our @EXPORT = qw(get_credit_remaining get_all_email_addresses);
 
 sub get_credit_remaining {
   my $vc               = shift;
@@ -50,4 +52,42 @@ SQL
   return $credit_remaining;
 }
 
+sub get_all_email_addresses {
+  my ($self) = @_;
+
+  my $is_sales = ref $self eq 'SL::DB::Customer';
+
+  my @addresses;
+
+  # billing address
+  push @addresses, $self->$_ for qw(email cc bcc);
+  if ($is_sales) {
+    push @addresses, $self->$_ for qw(delivery_order_mail invoice_mail);
+  }
+
+  # additional billing addresses
+  if ($is_sales) {
+    foreach my $additional_billing_address (@{ $self->additional_billing_addresses }) {
+      push @addresses, $additional_billing_address->$_ for qw(email);
+    }
+  }
+
+  # contacts
+  foreach my $contact (@{ $self->contacts }) {
+    push @addresses, $contact->$_ for qw(cp_email cp_privatemail);
+  }
+
+  # shiptos
+  foreach my $shipto (@{ $self->shipto }) {
+    push @addresses, $shipto->$_ for qw(shiptoemail);
+  }
+
+  # remove empty ones and duplicates
+  @addresses = grep { $_ } @addresses;
+  @addresses = uniq @addresses;
+
+
+  return \@addresses;
+}
+
 1;
index 8224172..76ee1b8 100644 (file)
--- a/SL/DN.pm
+++ b/SL/DN.pm
@@ -487,13 +487,17 @@ sub send_email {
     } or die $main::locale->text('No email for user with login #1 defined.', $ref->{invoice_employee_login});
   }
 
+  my $html_template = SL::Template::create(type => 'HTML',      form => $form, myconfig => $myconfig);
+  $html_template->set_tag_style('&lt;%', '%&gt;');
+
   my $template     = SL::Template::create(type => 'PlainText', form => $form, myconfig => $myconfig);
   my $mail         = Mailer->new();
   $mail->{bcc}     = $form->get_bcc_defaults($myconfig, $form->{bcc});
   $mail->{from}    = $from;
   $mail->{to}      = $ref->{recipient};
   $mail->{subject} = $template->parse_block($ref->{email_subject});
-  $mail->{message} = $template->parse_block($ref->{email_body});
+  $mail->{message} = $html_template->parse_block($ref->{email_body});
+  $mail->{content_type} = 'text/html';
   my $sign_backup  = $::myconfig{signature};
   $::myconfig{signature} = $sign if $sign;
   $mail->{message} .= $form->create_email_signature();
@@ -653,8 +657,9 @@ sub get_invoices {
          ct.name AS customername, a.customer_id, a.duedate,
          a.amount - a.paid AS open_amount,
          a.direct_debit,
+         pt.description as payment_term,
          dep.description as departmentname,
-
+         ct.invoice_mail AS cv_email,
          cfg.dunning_description, cfg.dunning_level,
 
          d.transdate AS dunning_date, d.duedate AS dunning_duedate,
@@ -672,6 +677,7 @@ sub get_invoices {
 
        LEFT JOIN customer ct ON (a.customer_id = ct.id)
        LEFT JOIN department dep ON (a.department_id = dep.id)
+       LEFT JOIN payment_terms pt ON (a.payment_id = pt.id)
        LEFT JOIN dunning_config cfg ON (a.dunning_config_id = cfg.id)
        LEFT JOIN dunning_config nextcfg ON
          (nextcfg.id =
@@ -963,7 +969,7 @@ sub print_dunning {
          c.country,           c.department_1, c.department_2, c.email,     c.customernumber,
          c.greeting,          c.contact,      c.phone,        c.fax,       c.homepage,
          c.email,             c.taxincluded,  c.business_id,  c.taxnumber, c.iban,
-         c.ustid,
+         c.ustid,             c.currency_id,  curr.name as currency,
          ar.id AS invoice_id,
          co.*
        FROM dunning d
@@ -971,6 +977,7 @@ sub print_dunning {
        LEFT JOIN customer c  ON (ar.customer_id = c.id)
        LEFT JOIN contacts co ON (ar.cp_id = co.cp_id)
        LEFT JOIN employee e  ON (ar.salesman_id = e.id)
+       LEFT JOIN currencies curr ON (c.currency_id = curr.id)
        WHERE (d.dunning_id = ?)
        LIMIT 1|;
   my $ref = selectfirst_hashref_query($form, $dbh, $query, $dunning_id);
@@ -1217,6 +1224,7 @@ sub print_original_invoice {
                      longdescription => 'html',
                      partnotes       => 'html',
                      notes           => 'html',
+                     $print_form->get_variable_content_types_for_cvars,
                    },
   );
 
index 8f04ce7..ebc6051 100644 (file)
--- a/SL/DO.pm
+++ b/SL/DO.pm
@@ -42,6 +42,7 @@ use SL::AM;
 use SL::Common;
 use SL::CVar;
 use SL::DB::DeliveryOrder;
+use SL::DB::DeliveryOrder::TypeData qw(:types is_valid_type);
 use SL::DB::Status;
 use SL::DBUtils;
 use SL::Helper::ShippedQty;
@@ -79,6 +80,7 @@ sub transactions {
          dord.transaction_description, dord.itime::DATE AS insertdate,
          pr.projectnumber AS globalprojectnumber,
          dep.description AS department,
+         dord.order_type,
          e.name AS employee,
          sm.name AS salesman
        FROM delivery_orders dord
@@ -90,7 +92,10 @@ sub transactions {
        LEFT JOIN department dep ON (dord.department_id = dep.id)
 |;
 
-  push @where, ($form->{type} eq 'sales_delivery_order' ? '' : 'NOT ') . qq|COALESCE(dord.is_sales, FALSE)|;
+  if ($form->{type} && is_valid_type($form->{type})) {
+    push @where, 'dord.order_type = ?';
+    push @values, $form->{type};
+  }
 
   if ($form->{department_id}) {
     push @where,  qq|dord.department_id = ?|;
@@ -129,7 +134,8 @@ sub transactions {
     push @where, "dord.$item = ?";
     push @values, conv_i($form->{$item});
   }
-  if ( !(($vc eq 'customer' && $main::auth->assert('sales_all_edit', 1)) || ($vc eq 'vendor' && $main::auth->assert('purchase_all_edit', 1))) ) {
+  if ( !(    ($vc eq 'customer' && ($main::auth->assert('sales_all_edit',    1) || $main::auth->assert('sales_delivery_order_view',    1)))
+          || ($vc eq 'vendor'   && ($main::auth->assert('purchase_all_edit', 1) || $main::auth->assert('purchase_delivery_order_view', 1))) ) ) {
     push @where, qq|dord.employee_id = (select id from employee where login= ?)|;
     push @values, $::myconfig{login};
   }
@@ -328,8 +334,8 @@ sub _save {
     $query = qq|SELECT nextval('id')|;
     ($form->{id}) = selectrow_query($form, $dbh, $query);
 
-    $query = qq|INSERT INTO delivery_orders (id, donumber, employee_id, currency_id, taxzone_id) VALUES (?, '', ?, (SELECT currency_id FROM defaults LIMIT 1), ?)|;
-    do_query($form, $dbh, $query, $form->{id}, conv_i($form->{employee_id}), $form->{taxzone_id});
+    $query = qq|INSERT INTO delivery_orders (id, donumber, employee_id, currency_id, taxzone_id, order_type) VALUES (?, '', ?, (SELECT currency_id FROM defaults LIMIT 1), ?, ?)|;
+    do_query($form, $dbh, $query, $form->{id}, conv_i($form->{employee_id}), $form->{taxzone_id}, SALES_DELIVERY_ORDER_TYPE);
   }
 
   my $project_id;
@@ -513,9 +519,9 @@ SQL
          donumber = ?, ordnumber = ?, cusordnumber = ?, transdate = ?, vendor_id = ?,
          customer_id = ?, reqdate = ?, tax_point = ?,
          shippingpoint = ?, shipvia = ?, notes = ?, intnotes = ?, closed = ?,
-         delivered = ?, department_id = ?, language_id = ?, shipto_id = ?,
+         delivered = ?, department_id = ?, language_id = ?, shipto_id = ?, billing_address_id = ?,
          globalproject_id = ?, employee_id = ?, salesman_id = ?, cp_id = ?, transaction_description = ?,
-         is_sales = ?, taxzone_id = ?, taxincluded = ?, payment_id = ?, currency_id = (SELECT id FROM currencies WHERE name = ?),
+         order_type = ?, taxzone_id = ?, taxincluded = ?, payment_id = ?, currency_id = (SELECT id FROM currencies WHERE name = ?),
          delivery_term_id = ?
        WHERE id = ?|;
 
@@ -525,11 +531,11 @@ SQL
              conv_date($form->{reqdate}), conv_date($form->{tax_point}), $form->{shippingpoint}, $form->{shipvia},
              $restricter->process($form->{notes}), $form->{intnotes},
              $form->{closed} ? 't' : 'f', $form->{delivered} ? "t" : "f",
-             conv_i($form->{department_id}), conv_i($form->{language_id}), conv_i($form->{shipto_id}),
+             conv_i($form->{department_id}), conv_i($form->{language_id}), conv_i($form->{shipto_id}), conv_i($form->{billing_address_id}),
              conv_i($form->{globalproject_id}), conv_i($form->{employee_id}),
              conv_i($form->{salesman_id}), conv_i($form->{cp_id}),
              $form->{transaction_description},
-             $form->{type} =~ /^sales/ ? 't' : 'f',
+             $form->{type} =~ /^sales/ ? SALES_DELIVERY_ORDER_TYPE : PURCHASE_DELIVERY_ORDER_TYPE,
              conv_i($form->{taxzone_id}), $form->{taxincluded} ? 't' : 'f', conv_i($form->{payment_id}), $form->{currency},
              conv_i($form->{delivery_term_id}),
              conv_i($form->{id}));
@@ -731,7 +737,7 @@ sub retrieve {
          dord.${vc}_id, cv.name AS ${vc},
          dord.closed, dord.reqdate, dord.department_id, dord.cusordnumber,
          d.description AS department, dord.language_id,
-         dord.shipto_id,
+         dord.shipto_id, dord.billing_address_id,
          dord.itime, dord.mtime,
          dord.globalproject_id, dord.delivered, dord.transaction_description,
          dord.taxzone_id, dord.taxincluded, dord.payment_id, (SELECT cu.name FROM currencies cu WHERE cu.id=dord.currency_id) AS currency,
index 2f289d0..73f06d0 100644 (file)
@@ -20,6 +20,7 @@ our %EXPORT_TAGS = (ALL => \@EXPORT_OK);
 
 use SL::DB::Invoice;
 use SL::DB::InvoiceItem;
+use SL::DB::DeliveryOrder::TypeData qw(:types);
 use SL::DB::Employee;
 use SL::Dev::Part qw(new_part);
 use SL::Dev::CustomerVendor qw(new_vendor new_customer);
@@ -116,7 +117,7 @@ sub create_sales_delivery_order {
   die "illegal customer" unless ref($customer) eq 'SL::DB::Customer';
 
   my $delivery_order = SL::DB::DeliveryOrder->new(
-    'is_sales'   => 'true',
+    order_type   => SALES_DELIVERY_ORDER_TYPE,
     'closed'     => undef,
     customer_id  => $customer->id,
     taxzone_id   => $customer->taxzone_id,
@@ -144,7 +145,7 @@ sub create_purchase_delivery_order {
   die "illegal customer" unless ref($vendor) eq 'SL::DB::Vendor';
 
   my $delivery_order = SL::DB::DeliveryOrder->new(
-    'is_sales'   => 'false',
+    order_type   => PURCHASE_DELIVERY_ORDER_TYPE,
     'closed'     => undef,
     vendor_id    => $vendor->id,
     taxzone_id   => $vendor->taxzone_id,
index b1eaf00..822e31f 100644 (file)
--- a/SL/FU.pm
+++ b/SL/FU.pm
@@ -195,8 +195,10 @@ sub follow_ups {
   my @values_user   = ();
 
   if ($params{trans_id}) {
-    $where .= qq| AND EXISTS (SELECT * FROM follow_up_links ful
-                              WHERE (ful.follow_up_id = fu.id) AND (ful.trans_id = ?))|;
+    $where .= qq| AND fu.id IN (select follow_up_id from follow_up_links where trans_id = ?)|;
+   # $where .= qq| AND (ful.follow_up_id = fu.id) AND (ful.trans_id = ?))|;
+   # $where .= qq| AND EXISTS (SELECT * FROM follow_up_links ful
+   #                           WHERE (ful.follow_up_id = fu.id) AND (ful.trans_id = ?))|;
     push @values, conv_i($params{trans_id});
   }
 
@@ -251,7 +253,7 @@ sub follow_ups {
     push @values, conv_i($params{created_for});
   }
 
-  if ($params{all_users}) {
+  if ($params{all_users} || $params{trans_id}) {  # trans_id only for documents?
     $where_user = qq|OR (fu.created_by IN (SELECT DISTINCT what FROM follow_up_access WHERE who = ?))|;
     push @values_user, $employee_id;
   }
index e232908..ca065e0 100644 (file)
@@ -21,11 +21,11 @@ use constant RENAME_NEW_VERSION => 4;
 
 sub get {
   my ($self, %params) = @_;
-  die 'no id' unless $params{id};
-  my $dbfile = SL::DB::Manager::File->get_first(query => [id => $params{id}]);
-  die 'not found' unless $dbfile;
-  $main::lxdebug->message(LXDebug->DEBUG2(), "object_id=".$dbfile->object_id." object_type=".$dbfile->object_type." dbfile=".$dbfile);
-  SL::File::Object->new(db_file => $dbfile, id => $dbfile->id, loaded => 1);
+  die "no id or dbfile" unless $params{id} || $params{dbfile};
+  $params{dbfile} = SL::DB::Manager::File->get_first(query => [id => $params{id}]) if !$params{dbfile};
+  die 'not found' unless $params{dbfile};
+  $main::lxdebug->message(LXDebug->DEBUG2(), "object_id=".$params{dbfile}->object_id." object_type=".$params{dbfile}->object_type." dbfile=".$params{dbfile});
+  SL::File::Object->new(db_file => $params{dbfile}, id => $params{dbfile}->id, loaded => 1);
 }
 
 sub get_version_count {
@@ -48,10 +48,11 @@ sub get_all {
     object_id   => $params{object_id},
     object_type => $params{object_type}
   );
-  push @query, (file_name => $params{file_name}) if $params{file_name};
-  push @query, (file_type => $params{file_type}) if $params{file_type};
-  push @query, (mime_type => $params{mime_type}) if $params{mime_type};
-  push @query, (source    => $params{source})    if $params{source};
+  push @query, (file_name     => $params{file_name})     if $params{file_name};
+  push @query, (file_type     => $params{file_type})     if $params{file_type};
+  push @query, (mime_type     => $params{mime_type})     if $params{mime_type};
+  push @query, (source        => $params{source})        if $params{source};
+  push @query, (print_variant => $params{print_variant}) if $params{print_variant};
 
   my $sortby = $params{sort_by} || 'itime DESC,file_name ASC';
 
@@ -62,9 +63,9 @@ sub get_all {
 sub get_all_versions {
   my ($self, %params) = @_;
   my @versionobjs;
-  my @fileobjs = $self->get_all(%params);
+  my @fileobjs;
   if ( $params{dbfile} ) {
-    push @fileobjs, SL::File::Object->new(dbfile => $params{db_file}, id => $params{dbfile}->id, loaded => 1);
+    push @fileobjs, SL::File::Object->new(db_file => $params{dbfile}, id => $params{dbfile}->id, loaded => 1);
   } else {
     @fileobjs = $self->get_all(%params);
   }
@@ -98,10 +99,11 @@ sub get_all_count {
     object_id   => $params{object_id},
     object_type => $params{object_type}
   );
-  push @query, (file_name => $params{file_name}) if $params{file_name};
-  push @query, (file_type => $params{file_type}) if $params{file_type};
-  push @query, (mime_type => $params{mime_type}) if $params{mime_type};
-  push @query, (source    => $params{source})    if $params{source};
+  push @query, (file_name     => $params{file_name})     if $params{file_name};
+  push @query, (file_type     => $params{file_type})     if $params{file_type};
+  push @query, (mime_type     => $params{mime_type})     if $params{mime_type};
+  push @query, (source        => $params{source})        if $params{source};
+  push @query, (print_variant => $params{print_variant}) if $params{print_variant};
 
   my $cnt = SL::DB::Manager::File->get_all_count(query => [@query]);
   return $cnt;
@@ -218,6 +220,7 @@ sub _save {
         mime_type      => $params{mime_type},
         title          => $params{title},
         description    => $params{description},
+        print_variant  => $params{print_variant},
       );
       $file->itime($params{mtime})    if $params{mtime};
       $params{itime} = $params{mtime} if $params{mtime};
index 9daef35..758142b 100644 (file)
@@ -6,6 +6,7 @@ use parent qw(SL::File::Backend);
 use SL::DB::File;
 use File::Copy;
 use File::Slurp;
+use File::stat;
 use File::Path qw(make_path);
 
 #
@@ -66,6 +67,15 @@ sub save {
   die 'dbfile not exists' unless $params{dbfile};
   my $dbfile = $params{dbfile};
   die 'no file contents' unless $params{file_path} || $params{file_contents};
+
+  # Do not save and do not create a new version of the document if file size of last version is the same.
+  if ($dbfile->source eq 'created' && $self->get_version_count(dbfile => $dbfile)) {
+    my $new_file_size  = $params{file_path} ? stat($params{file_path})->size : length($params{file_contents});
+    my $last_file_size = stat($self->_filesystem_path($dbfile))->size;
+
+    return 1 if $last_file_size == $new_file_size;
+  }
+
   $dbfile->backend_data(0) unless $dbfile->backend_data;
   $dbfile->backend_data($dbfile->backend_data*1+1);
   $dbfile->save->load;
@@ -88,7 +98,7 @@ sub save {
 sub get_version_count {
   my ($self, %params) = @_;
   die "no dbfile" unless $params{dbfile};
-  return $params{dbfile}->backend_data * 1;
+  return $params{dbfile}->backend_data//0 * 1;
 }
 
 sub get_mtime {
@@ -100,8 +110,7 @@ sub get_mtime {
 
   die "No file found at $path. Expected: $params{dbfile}{file_name}, file.id: $params{dbfile}{id}" if !-f $path;
 
-  my @st = stat($path);
-  my $dt = DateTime->from_epoch(epoch => $st[9], time_zone => $::locale->get_local_time_zone()->name, locale => $::lx_office_conf{system}->{language})->clone();
+  my $dt = DateTime->from_epoch(epoch => stat($path)->mtime, time_zone => $::locale->get_local_time_zone()->name, locale => $::lx_office_conf{system}->{language})->clone();
   return $dt;
 }
 
index 40e1398..bf8f9af 100644 (file)
@@ -5,12 +5,13 @@ use strict;
 use parent qw(SL::File::Backend);
 use SL::DB::File;
 
-#use SL::Webdav;
+use SL::System::Process;
 use File::Copy;
 use File::Slurp;
 use File::Basename;
 use File::Path qw(make_path);
 use File::MimeInfo::Magic;
+use File::stat;
 
 #
 # public methods
@@ -73,9 +74,8 @@ sub get_mtime {
   die "no dbfile" unless $params{dbfile};
   $main::lxdebug->message(LXDebug->DEBUG2(), "version=" .$params{version});
   my ($path, undef, undef) = $self->webdav_path($params{dbfile});
-  die "no file found in backend" if !-f $path;
-  my @st = stat($path);
-  my $dt = DateTime->from_epoch(epoch => $st[9])->clone();
+  die "No file found in Backend: " . $path unless -f $path;
+  my $dt = DateTime->from_epoch(epoch => stat($path)->mtime, time_zone => $::locale->get_local_time_zone()->name)->clone();
   $main::lxdebug->message(LXDebug->DEBUG2(), "dt=" .$dt);
   return $dt;
 }
@@ -84,7 +84,7 @@ sub get_filepath {
   my ($self, %params) = @_;
   die "no dbfile" unless $params{dbfile};
   my ($path, undef, undef) = $self->webdav_path($params{dbfile});
-  die "no file" if !-f $path;
+  die "No file found in Backend: " . $path unless -f $path;
   return $path;
 }
 
@@ -105,8 +105,7 @@ sub sync_from_backend {
 }
 
 sub enabled {
-  return 0 unless $::instance_conf->get_doc_webdav;
-  return 1;
+  return $::instance_conf->get_doc_webdav;
 }
 
 #
@@ -114,47 +113,51 @@ sub enabled {
 #
 
 my %type_to_path = (
-  sales_quotation         => 'angebote',
-  sales_order             => 'bestellungen',
-  request_quotation       => 'anfragen',
-  purchase_order          => 'lieferantenbestellungen',
-  sales_delivery_order    => 'verkaufslieferscheine',
-  purchase_delivery_order => 'einkaufslieferscheine',
-  credit_note             => 'gutschriften',
-  invoice                 => 'rechnungen',
-  purchase_invoice        => 'einkaufsrechnungen',
-  part                    => 'waren',
-  service                 => 'dienstleistungen',
-  assembly                => 'erzeugnisse',
-  letter                  => 'briefe',
-  general_ledger          => 'dialogbuchungen',
-  gl_transaction          => 'dialogbuchungen',
-  accounts_payable        => 'kreditorenbuchungen',
-  shop_image              => 'shopbilder',
-  customer                => 'kunden',
-  vendor                  => 'lieferanten',
+  sales_quotation             => 'angebote',
+  sales_order                 => 'bestellungen',
+  request_quotation           => 'anfragen',
+  purchase_order              => 'lieferantenbestellungen',
+  sales_delivery_order        => 'verkaufslieferscheine',
+  purchase_delivery_order     => 'einkaufslieferscheine',
+  credit_note                 => 'gutschriften',
+  invoice                     => 'rechnungen',
+  invoice_for_advance_payment => 'rechnungen',
+  final_invoice               => 'rechnungen',
+  purchase_invoice            => 'einkaufsrechnungen',
+  part                        => 'waren',
+  service                     => 'dienstleistungen',
+  assembly                    => 'erzeugnisse',
+  letter                      => 'briefe',
+  general_ledger              => 'dialogbuchungen',
+  gl_transaction              => 'dialogbuchungen',
+  accounts_payable            => 'kreditorenbuchungen',
+  shop_image                  => 'shopbilder',
+  customer                    => 'kunden',
+  vendor                      => 'lieferanten',
 );
 
 my %type_to_model = (
-  sales_quotation         => 'Order',
-  sales_order             => 'Order',
-  request_quotation       => 'Order',
-  purchase_order          => 'Order',
-  sales_delivery_order    => 'DeliveryOrder',
-  purchase_delivery_order => 'DeliveryOrder',
-  credit_note             => 'Invoice',
-  invoice                 => 'Invoice',
-  purchase_invoice        => 'PurchaseInvoice',
-  part                    => 'Part',
-  service                 => 'Part',
-  assembly                => 'Part',
-  letter                  => 'Letter',
-  general_ledger          => 'GLTransaction',
-  gl_transaction          => 'GLTransaction',
-  accounts_payable        => 'GLTransaction',
-  shop_image              => 'Part',
-  customer                => 'Customer',
-  vendor                  => 'Vendor',
+  sales_quotation             => 'Order',
+  sales_order                 => 'Order',
+  request_quotation           => 'Order',
+  purchase_order              => 'Order',
+  sales_delivery_order        => 'DeliveryOrder',
+  purchase_delivery_order     => 'DeliveryOrder',
+  credit_note                 => 'Invoice',
+  invoice                     => 'Invoice',
+  invoice_for_advance_payment => 'Invoice',
+  final_invoice               => 'Invoice',
+  purchase_invoice            => 'PurchaseInvoice',
+  part                        => 'Part',
+  service                     => 'Part',
+  assembly                    => 'Part',
+  letter                      => 'Letter',
+  general_ledger              => 'GLTransaction',
+  gl_transaction              => 'GLTransaction',
+  accounts_payable            => 'GLTransaction',
+  shop_image                  => 'Part',
+  customer                    => 'Customer',
+  vendor                      => 'Vendor',
 );
 
 my %model_to_number = (
@@ -206,17 +209,7 @@ sub webdav_path {
   return (File::Spec->catfile($path, $fname), $path, $fname);
 }
 
-sub get_rootdir {
-  my ($self) = @_;
-
-  #TODO immer noch das alte Problem:
-  #je nachdem von woher der Aufruf kommt ist man in ./users oder .
-  my $rootdir  = POSIX::getcwd();
-  my $basename = basename($rootdir);
-  my $dirname  = dirname($rootdir);
-  $rootdir = $dirname if $basename eq 'users';
-  return $rootdir;
-}
+sub get_rootdir { SL::System::Process::exe_dir() }
 
 sub _get_number_from_model {
   my ($self, $dbfile) = @_;
@@ -346,5 +339,3 @@ The synchronization must be tested and a periodical task is needed to synchroniz
 Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>
 
 =cut
-
-
index 8d8f417..fd79b96 100644 (file)
@@ -59,7 +59,9 @@ use SL::CVar;
 use SL::DB;
 use SL::DBConnect;
 use SL::DBUtils;
+use SL::DB::AdditionalBillingAddress;
 use SL::DB::Customer;
+use SL::DB::CustomVariableConfig;
 use SL::DB::Default;
 use SL::DB::PaymentTerm;
 use SL::DB::Vendor;
@@ -387,6 +389,7 @@ sub create_http_response {
                                      '-path'    => $uri->path,
                                      '-expires' => '+' . $::auth->{session_timeout} . 'm',
                                      '-secure'  => $::request->is_https);
+      $session_cookie = "$session_cookie; SameSite=strict";
     }
   }
 
@@ -434,6 +437,8 @@ sub header {
     common part_selection
   ), "jquery/ui/i18n/jquery.ui.datepicker-$::myconfig{countrycode}");
 
+  $layout->use_javascript("$_.js") for @{ $params{use_javascripts} // [] };
+
   $self->{favicon} ||= "favicon.ico";
   $self->{titlebar} = join ' - ', grep $_, $self->{title}, $self->{login}, $::myconfig{dbname}, $self->read_version if $self->{title} || !$self->{titlebar};
 
@@ -709,74 +714,6 @@ sub format_amount {
   SL::Helper::Number::_format_number($amount, $places, %$myconfig, dash => $dash);
 }
 
-sub format_amount_units {
-  $main::lxdebug->enter_sub();
-
-  my $self             = shift;
-  my %params           = @_;
-
-  my $myconfig         = \%main::myconfig;
-  my $amount           = $params{amount} * 1;
-  my $places           = $params{places};
-  my $part_unit_name   = $params{part_unit};
-  my $amount_unit_name = $params{amount_unit};
-  my $conv_units       = $params{conv_units};
-  my $max_places       = $params{max_places};
-
-  if (!$part_unit_name) {
-    $main::lxdebug->leave_sub();
-    return '';
-  }
-
-  my $all_units        = AM->retrieve_all_units;
-
-  if (('' eq ref $conv_units) && ($conv_units =~ /convertible/)) {
-    $conv_units = AM->convertible_units($all_units, $part_unit_name, $conv_units eq 'convertible_not_smaller');
-  }
-
-  if (!scalar @{ $conv_units }) {
-    my $result = $self->format_amount($myconfig, $amount, $places, undef, $max_places) . " " . $part_unit_name;
-    $main::lxdebug->leave_sub();
-    return $result;
-  }
-
-  my $part_unit  = $all_units->{$part_unit_name};
-  my $conv_unit  = ($amount_unit_name && ($amount_unit_name ne $part_unit_name)) ? $all_units->{$amount_unit_name} : $part_unit;
-
-  $amount       *= $conv_unit->{factor};
-
-  my @values;
-  my $num;
-
-  foreach my $unit (@$conv_units) {
-    my $last = $unit->{name} eq $part_unit->{name};
-    if (!$last) {
-      $num     = int($amount / $unit->{factor});
-      $amount -= $num * $unit->{factor};
-    }
-
-    if ($last ? $amount : $num) {
-      push @values, { "unit"   => $unit->{name},
-                      "amount" => $last ? $amount / $unit->{factor} : $num,
-                      "places" => $last ? $places : 0 };
-    }
-
-    last if $last;
-  }
-
-  if (!@values) {
-    push @values, { "unit"   => $part_unit_name,
-                    "amount" => 0,
-                    "places" => 0 };
-  }
-
-  my $result = join " ", map { $self->format_amount($myconfig, $_->{amount}, $_->{places}, undef, $max_places), $_->{unit} } @values;
-
-  $main::lxdebug->leave_sub();
-
-  return $result;
-}
-
 sub format_string {
   $main::lxdebug->enter_sub(2);
 
@@ -923,6 +860,9 @@ sub parse_template {
   # therefore copy to webdav, even if we do not have the webdav feature enabled (just archive)
   my $copy_to_webdav =  $::instance_conf->get_webdav_documents && !$self->{preview} && $self->{tmpdir} && $self->{tmpfile} && $self->{type}
                         && $self->{type} ne 'statement';
+
+  $self->{attachment_filename} ||= $self->generate_attachment_filename;
+
   if ( $ext_for_format eq 'pdf' && $self->doc_storage_enabled ) {
     $self->append_general_pdf_attachments(filepath =>  $self->{tmpdir}."/".$self->{tmpfile},
                                           type     =>  $self->{type});
@@ -939,7 +879,6 @@ sub parse_template {
 
     if (!$self->{preview} && $self->{attachment_type} !~ m{^dunning} && $self->doc_storage_enabled)
     {
-      $self->{attachment_filename} ||= $self->generate_attachment_filename;
       $self->store_pdf($self);
     }
     $self->cleanup;
@@ -958,7 +897,6 @@ sub parse_template {
   }
 
   if ( !$self->{preview} && $ext_for_format eq 'pdf' && $self->{attachment_type} !~ m{^dunning} && $self->doc_storage_enabled) {
-    $self->{attachment_filename} ||= $self->generate_attachment_filename;
     my $file_obj = $self->store_pdf($self);
     $self->{print_file_id} = $file_obj->id if $file_obj;
   }
@@ -1017,17 +955,15 @@ sub send_email {
   $mail->{to}     = $self->{EMAIL_RECIPIENT} ? $self->{EMAIL_RECIPIENT} : $self->{email};
   $mail->{from}   = qq|"$myconfig->{name}" <$myconfig->{email}>|;
   $mail->{fileid} = time() . '.' . $$ . '.';
+  $mail->{content_type}  =  "text/html";
   my $full_signature     =  $self->create_email_signature();
-  $full_signature        =~ s/\r//g;
 
   $mail->{attachments} =  [];
   my @attfiles;
   # if we send html or plain text inline
   if (($self->{format} eq 'html') && ($self->{sendmode} eq 'inline')) {
-    $mail->{content_type}   =  "text/html";
     $mail->{message}        =~ s/\r//g;
     $mail->{message}        =~ s{\n}{<br>\n}g;
-    $full_signature         =~ s{\n}{<br>\n}g;
     $mail->{message}       .=  $full_signature;
 
     open(IN, "<", $self->{tmpfile})
@@ -1040,9 +976,10 @@ sub send_email {
     $attachment_name     =~ s{\.(.+?)$}{.${ext_for_format}} if ($ext_for_format);
 
     if (($self->{attachment_policy} // '') eq 'old_file') {
-      my ( $attfile ) = SL::File->get_all(object_id   => $self->{id},
-                                          object_type => $self->{formname},
-                                          file_type   => 'document');
+      my ( $attfile ) = SL::File->get_all(object_id     => $self->{id},
+                                          object_type   => $self->{type},
+                                          file_type     => 'document',
+                                          print_variant => $self->{formname},);
 
       if ($attfile) {
         $attfile->{override_file_name} = $attachment_name if $attachment_name;
@@ -1151,26 +1088,31 @@ sub get_formname_translation {
   local $::locale = Locale->new($self->{recipient_locale});
 
   my %formname_translations = (
-    bin_list                => $main::locale->text('Bin List'),
-    credit_note             => $main::locale->text('Credit Note'),
-    invoice                 => $main::locale->text('Invoice'),
-    pick_list               => $main::locale->text('Pick List'),
-    proforma                => $main::locale->text('Proforma Invoice'),
-    purchase_order          => $main::locale->text('Purchase Order'),
-    request_quotation       => $main::locale->text('RFQ'),
-    sales_order             => $main::locale->text('Confirmation'),
-    sales_quotation         => $main::locale->text('Quotation'),
-    storno_invoice          => $main::locale->text('Storno Invoice'),
-    sales_delivery_order    => $main::locale->text('Delivery Order'),
-    purchase_delivery_order => $main::locale->text('Delivery Order'),
-    dunning                 => $main::locale->text('Dunning'),
-    dunning1                => $main::locale->text('Payment Reminder'),
-    dunning2                => $main::locale->text('Dunning'),
-    dunning3                => $main::locale->text('Last Dunning'),
-    dunning_invoice         => $main::locale->text('Dunning Invoice'),
-    letter                  => $main::locale->text('Letter'),
-    ic_supply               => $main::locale->text('Intra-Community supply'),
-    statement               => $main::locale->text('Statement'),
+    bin_list                    => $main::locale->text('Bin List'),
+    credit_note                 => $main::locale->text('Credit Note'),
+    invoice                     => $main::locale->text('Invoice'),
+    invoice_copy                => $main::locale->text('Invoice Copy'),
+    invoice_for_advance_payment => $main::locale->text('Invoice for Advance Payment'),
+    final_invoice               => $main::locale->text('Final Invoice'),
+    pick_list                   => $main::locale->text('Pick List'),
+    proforma                    => $main::locale->text('Proforma Invoice'),
+    purchase_order              => $main::locale->text('Purchase Order'),
+    request_quotation           => $main::locale->text('RFQ'),
+    sales_order                 => $main::locale->text('Confirmation'),
+    sales_quotation             => $main::locale->text('Quotation'),
+    storno_invoice              => $main::locale->text('Storno Invoice'),
+    sales_delivery_order        => $main::locale->text('Delivery Order'),
+    purchase_delivery_order     => $main::locale->text('Delivery Order'),
+    supplier_delivery_order     => $main::locale->text('Supplier Delivery Order'),
+    rma_delivery_order          => $main::locale->text('RMA Delivery Order'),
+    dunning                     => $main::locale->text('Dunning'),
+    dunning1                    => $main::locale->text('Payment Reminder'),
+    dunning2                    => $main::locale->text('Dunning'),
+    dunning3                    => $main::locale->text('Last Dunning'),
+    dunning_invoice             => $main::locale->text('Dunning Invoice'),
+    letter                      => $main::locale->text('Letter'),
+    ic_supply                   => $main::locale->text('Intra-Community supply'),
+    statement                   => $main::locale->text('Statement'),
   );
 
   $main::lxdebug->leave_sub();
@@ -1196,11 +1138,11 @@ sub get_number_prefix_for_type {
   my ($self) = @_;
 
   my $prefix =
-      (first { $self->{type} eq $_ } qw(invoice credit_note)) ? 'inv'
-    : ($self->{type} =~ /_quotation$/)                        ? 'quo'
-    : ($self->{type} =~ /_delivery_order$/)                   ? 'do'
-    : ($self->{type} =~ /letter/)                             ? 'letter'
-    :                                                           'ord';
+      (first { $self->{type} eq $_ } qw(invoice invoice_for_advance_payment final_invoice credit_note)) ? 'inv'
+    : ($self->{type} =~ /_quotation$/)                                                                  ? 'quo'
+    : ($self->{type} =~ /_delivery_order$/)                                                             ? 'do'
+    : ($self->{type} =~ /letter/)                                                                       ? 'letter'
+    :                                                                                                     'ord';
 
   # better default like this?
   # : ($self->{type} =~ /(sales|purcharse)_order/           :  'ord';
@@ -1235,7 +1177,7 @@ sub generate_attachment_filename {
   my $attachment_filename = $main::locale->unquote_special_chars('HTML', $self->get_formname_translation());
   my $prefix              = $self->get_number_prefix_for_type();
 
-  if ($self->{preview} && (first { $self->{type} eq $_ } qw(invoice credit_note))) {
+  if ($self->{preview} && (first { $self->{type} eq $_ } qw(invoice invoice_for_advance_payment final_invoice credit_note))) {
     $attachment_filename .= ' (' . $recipient_locale->text('Preview') . ')' . $self->get_extension_for_format();
 
   } elsif ($attachment_filename && $self->{"${prefix}number"}) {
@@ -1297,10 +1239,12 @@ sub generate_email_body {
 
   return undef unless $body;
 
+  $body .= GenericTranslations->get(translation_type => "salutation_punctuation_mark", language_id => $self->{language_id});
+  $body  = '<p>' . $::locale->quote_special_chars('HTML', $body) . '</p>';
+
   my $translation_type = $params{translation_type} // "preset_text_$self->{formname}";
   my $main_body        = GenericTranslations->get(translation_type => $translation_type,                  language_id => $self->{language_id});
   $main_body           = GenericTranslations->get(translation_type => $params{fallback_translation_type}, language_id => $self->{language_id}) if !$main_body && $params{fallback_translation_type};
-  $body               .= GenericTranslations->get(translation_type => "salutation_punctuation_mark",      language_id => $self->{language_id}) . "\n\n";
   $body               .= $main_body;
 
   $body = $main::locale->unquote_special_chars('HTML', $body);
@@ -2582,7 +2526,7 @@ sub create_links {
            a.mtime, a.itime,
            a.intnotes, a.department_id, a.amount AS oldinvtotal,
            a.paid AS oldtotalpaid, a.employee_id, a.gldate, a.type,
-           a.globalproject_id, ${extra_columns}
+           a.globalproject_id, a.transaction_description, ${extra_columns}
            c.name AS $table,
            d.description AS department,
            e.name AS employee
@@ -2779,19 +2723,48 @@ sub lastname_used {
 }
 
 sub get_variable_content_types {
-  my %html_variables  = (
-      longdescription => 'html',
-      partnotes       => 'html',
-      notes           => 'html',
-      orignotes       => 'html',
-      notes1          => 'html',
-      notes2          => 'html',
-      notes3          => 'html',
-      notes4          => 'html',
-      header_text     => 'html',
-      footer_text     => 'html',
+  my ($self) = @_;
+
+  my %html_variables = (
+    longdescription  => 'html',
+    partnotes        => 'html',
+    notes            => 'html',
+    orignotes        => 'html',
+    notes1           => 'html',
+    notes2           => 'html',
+    notes3           => 'html',
+    notes4           => 'html',
+    header_text      => 'html',
+    footer_text      => 'html',
   );
-  return \%html_variables;
+
+  return {
+    %html_variables,
+    $self->get_variable_content_types_for_cvars,
+  };
+}
+
+sub get_variable_content_types_for_cvars {
+  my ($self)       = @_;
+  my $html_configs = SL::DB::Manager::CustomVariableConfig->get_all(where => [ type => 'htmlfield' ]);
+  my %types;
+
+  if (@{ $html_configs }) {
+    my %prefix_by_module = (
+      Contacts => 'cp_cvar_',
+      CT       => 'vc_cvar_',
+      IC       => 'ic_cvar_',
+      Projects => 'project_cvar_',
+      ShipTo   => 'shiptocvar_',
+    );
+
+    foreach my $cfg (@{ $html_configs }) {
+      my $prefix = $prefix_by_module{$cfg->module};
+      $types{$prefix . $cfg->name} = 'html' if $prefix;
+    }
+  }
+
+  return %types;
 }
 
 sub current_date {
@@ -2978,6 +2951,8 @@ sub save_status {
 # $main::locale->text('UNDO TRANSFER')
 # $main::locale->text('UNIMPORT')
 # $main::locale->text('invoice')
+# $main::locale->text('invoice_for_advance_payment')
+# $main::locale->text('final_invoice')
 # $main::locale->text('proforma')
 # $main::locale->text('sales_order')
 # $main::locale->text('pick_list')
@@ -3022,7 +2997,7 @@ sub get_history {
       qq|SELECT h.employee_id, h.itime::timestamp(0) AS itime, h.addition, h.what_done, emp.name, h.snumbers, h.trans_id AS id | .
       qq|FROM history_erp h | .
       qq|LEFT JOIN employee emp ON (emp.id = h.employee_id) | .
-      qq|WHERE (trans_id = | . $trans_id . qq|) $restriction | .
+      qq|WHERE (trans_id = | . $dbh->quote($trans_id) . qq|) $restriction | .
       $order;
 
     my $sth = $dbh->prepare($query) || $self->dberror($query);
@@ -3221,6 +3196,8 @@ sub prepare_for_printing {
     IS->invoice_details(\%::myconfig, $self, $::locale);
   }
 
+  $self->set_addition_billing_address_print_variables;
+
   # Chose extension & set source file name
   my $extension = 'html';
   if ($self->{format} eq 'postscript') {
@@ -3281,6 +3258,43 @@ sub prepare_for_printing {
     today     => DateTime->today,
   };
 
+  if ($defaults->print_interpolate_variables_in_positions) {
+    $self->substitute_placeholders_in_template_arrays({ field => 'description', type => 'text' }, { field => 'longdescription', type => 'html' });
+  }
+
+  return $self;
+}
+
+sub set_addition_billing_address_print_variables {
+  my ($self) = @_;
+
+  return if !$self->{billing_address_id};
+
+  my $address = SL::DB::Manager::AdditionalBillingAddress->find_by(id => $self->{billing_address_id});
+  return if !$address;
+
+  $self->{"billing_address_${_}"} = $address->$_ for map { $_->name } @{ $address->meta->columns };
+}
+
+sub substitute_placeholders_in_template_arrays {
+  my ($self, @fields) = @_;
+
+  foreach my $spec (@fields) {
+    $spec     = { field => $spec, type => 'text' } if !ref($spec);
+    my $field = $spec->{field};
+
+    next unless exists $self->{TEMPLATE_ARRAYS} && exists $self->{TEMPLATE_ARRAYS}->{$field};
+
+    my $tag_start = $spec->{type} eq 'html' ? '&lt;%' : '<%';
+    my $tag_end   = $spec->{type} eq 'html' ? '%&gt;' : '%>';
+    my $formatter = $spec->{type} eq 'html' ? sub { $::locale->quote_special_chars('html', $_[0] // '') } : sub { $_[0] };
+
+    $self->{TEMPLATE_ARRAYS}->{$field} = [
+      apply { s{${tag_start}(.+?)${tag_end}}{ $formatter->($self->{$1}) }eg }
+        @{ $self->{TEMPLATE_ARRAYS}->{$field} }
+    ];
+  }
+
   return $self;
 }
 
@@ -3435,19 +3449,11 @@ sub reformat_numbers {
 }
 
 sub create_email_signature {
-
   my $client_signature = $::instance_conf->get_signature;
   my $user_signature   = $::myconfig{signature};
 
-  my $signature = '';
-  if ( $client_signature or $user_signature ) {
-    $signature  = "\n\n-- \n";
-    $signature .= $user_signature   . "\n" if $user_signature;
-    $signature .= $client_signature . "\n" if $client_signature;
-  };
-  return $signature;
-
-};
+  return join '', grep { $_ } ($user_signature, $client_signature);
+}
 
 sub calculate_tax {
   # this function calculates the net amount and tax for the lines in ar, ap and
index 4c892e7..46c2d49 100644 (file)
--- a/SL/GL.pm
+++ b/SL/GL.pm
@@ -124,12 +124,14 @@ sub _post_transaction {
     qq|UPDATE gl SET
          reference = ?, description = ?, notes = ?,
          transdate = ?, deliverydate = ?, tax_point = ?, department_id = ?, taxincluded = ?,
-         storno = ?, storno_id = ?, ob_transaction = ?, cb_transaction = ?
+         storno = ?, storno_id = ?, ob_transaction = ?, cb_transaction = ?,
+         transaction_description = ?
        WHERE id = ?|;
 
   @values = ($form->{reference}, $form->{description}, $form->{notes},
              conv_date($form->{transdate}), conv_date($form->{deliverydate}), conv_date($form->{tax_point}), conv_i($form->{department_id}), $form->{taxincluded} ? 't' : 'f',
              $form->{storno} ? 't' : 'f', conv_i($form->{storno_id}), $form->{ob_transaction} ? 't' : 'f', $form->{cb_transaction} ? 't' : 'f',
+             $form->{transaction_description},
              conv_i($form->{id}));
   do_query($form, $dbh, $query, @values);
 
@@ -299,6 +301,15 @@ sub all_transactions {
     push(@apvalues, like($form->{notes}));
   }
 
+  if (trim($form->{transaction_description})) {
+    $glwhere .= " AND g.transaction_description ILIKE ?";
+    $arwhere .= " AND a.transaction_description ILIKE ?";
+    $apwhere .= " AND a.transaction_description ILIKE ?";
+    push(@glvalues, like($form->{transaction_description}));
+    push(@arvalues, like($form->{transaction_description}));
+    push(@apvalues, like($form->{transaction_description}));
+  }
+
   if ($form->{accno}) {
     $glwhere .= " AND c.accno = '$form->{accno}'";
     $arwhere .= " AND c.accno = '$form->{accno}'";
@@ -355,18 +366,20 @@ sub all_transactions {
   }
 
   my %sort_columns =  (
-    'id'           => [ qw(id)                   ],
-    'transdate'    => [ qw(transdate id)         ],
-    'gldate'       => [ qw(gldate id)         ],
-    'reference'    => [ qw(lower_reference id)   ],
-    'description'  => [ qw(lower_description id) ],
-    'accno'        => [ qw(accno transdate id)   ],
-    'department'   => [ qw(department transdate id)   ],
+    'id'                      => [ qw(id)                   ],
+    'transdate'               => [ qw(transdate id)         ],
+    'gldate'                  => [ qw(gldate id)         ],
+    'reference'               => [ qw(lower_reference id)   ],
+    'description'             => [ qw(lower_description id) ],
+    'accno'                   => [ qw(accno transdate id)   ],
+    'department'              => [ qw(department transdate id)   ],
+    'transaction_description' => [ qw(lower_transaction_description id) ],
     );
   my %lowered_columns =  (
-    'reference'       => { 'gl' => 'g.reference',   'arap' => 'a.invnumber', },
-    'source'          => { 'gl' => 'ac.source',     'arap' => 'ac.source',   },
-    'description'     => { 'gl' => 'g.description', 'arap' => 'ct.name',     },
+    'reference'               => { 'gl' => 'g.reference',               'arap' => 'a.invnumber',               },
+    'source'                  => { 'gl' => 'ac.source',                 'arap' => 'ac.source',                 },
+    'description'             => { 'gl' => 'g.description',             'arap' => 'ct.name',                   },
+    'transaction_description' => { 'gl' => 'g.transaction_description', 'arap' => 'a.transaction_description', },
     );
 
   # sortdir = sort direction (ascending or descending)
@@ -387,7 +400,7 @@ sub all_transactions {
         ac.acc_trans_id, g.id, 'gl' AS type, FALSE AS invoice, g.reference, ac.taxkey, c.link,
         g.description, ac.transdate, ac.gldate, ac.source, ac.trans_id,
         ac.amount, c.accno, g.notes, t.chart_id,
-        d.description AS department,
+        d.description AS department, g.transaction_description,
         CASE WHEN (COALESCE(e.name, '') = '') THEN e.login ELSE e.name END AS employee
         $project_columns $gl_globalproject_columns
         $columns_for_sorting{gl}
@@ -405,7 +418,7 @@ sub all_transactions {
       SELECT ac.acc_trans_id, a.id, 'ar' AS type, a.invoice, a.invnumber, ac.taxkey, c.link,
         ct.name, ac.transdate, ac.gldate, ac.source, ac.trans_id,
         ac.amount, c.accno, a.notes, t.chart_id,
-        d.description AS department,
+        d.description AS department, a.transaction_description,
         CASE WHEN (COALESCE(e.name, '') = '') THEN e.login ELSE e.name END AS employee
         $project_columns $arap_globalproject_columns
         $columns_for_sorting{arap}
@@ -425,7 +438,7 @@ sub all_transactions {
       SELECT ac.acc_trans_id, a.id, 'ap' AS type, a.invoice, a.invnumber, ac.taxkey, c.link,
         ct.name, ac.transdate, ac.gldate, ac.source, ac.trans_id,
         ac.amount, c.accno, a.notes, t.chart_id,
-        d.description AS department,
+        d.description AS department, a.transaction_description,
         CASE WHEN (COALESCE(e.name, '') = '') THEN e.login ELSE e.name END AS employee
         $project_columns $arap_globalproject_columns
         $columns_for_sorting{arap}
@@ -657,7 +670,8 @@ sub transaction {
            g.storno, g.storno_id,
            g.department_id, d.description AS department,
            e.name AS employee, g.taxincluded, g.gldate,
-         g.ob_transaction, g.cb_transaction
+           g.ob_transaction, g.cb_transaction,
+           g.transaction_description
          FROM gl g
          LEFT JOIN department d ON (d.id = g.department_id)
          LEFT JOIN employee e ON (e.id = g.employee_id)
index f68fb0a..0703186 100644 (file)
@@ -27,7 +27,7 @@ sub strip {
   if (!%stripper) {
     %stripper = ( parser => HTML::Parser->new );
 
-    $stripper{parser}->handler(text => sub { $stripper{text} .= $_[1]; });
+    $stripper{parser}->handler(text => sub { $stripper{text} .= ' ' . $_[1]; });
   }
 
   $stripper{text} = '';
@@ -35,10 +35,37 @@ sub strip {
   $stripper{parser}->eof;
 
   $stripper{text} =~ s{\&([^;]+);}{ $entities{$1} || "\&$1;" }eg;
+  $stripper{text} =~ s{^ +| +$}{}g;
+  $stripper{text} =~ s{ {2,}}{ }g;
 
   return delete $stripper{text};
 }
 
+sub plain_text_to_html {
+  my ($class_or_text) = @_;
+
+  my $text = !ref($class_or_text) && (($class_or_text // '') eq 'SL::HTML::Util') ? $_[1] : $class_or_text;
+
+  return $text if $text =~ m{^<p>.*</p>$};
+
+  $text =~ s{\r+}{}g;
+  $text =~ s{^[[:space:]]+|[[:space:]]+$}{}g;
+
+  return '' if $text eq '';
+
+  my @paragraphs;
+
+  foreach my $paragraph (split m{\n{2,}}, $text) {
+    no warnings 'once';
+    $paragraph =  $::locale->quote_special_chars('HTML', $paragraph);
+    $paragraph =~ s{\n}{<br>}g;
+
+    push @paragraphs, $paragraph;
+  }
+
+  return '<p>' . join('</p><p>', @paragraphs) . '</p>';
+}
+
 1;
 __END__
 
@@ -63,6 +90,12 @@ SL::HTML::Util - Utility functions dealing with HTML
 Removes all HTML elements and tags from C<$html_content> and returns
 the remaining plain text.
 
+=item C<plain_text_to_html $text>
+
+Converts a plain text to HTML: paragraphs will be recognized by empty
+lines; remaining newlines will be converted into forced line breaks;
+the rest will be HTML escaped.
+
 =back
 
 =head1 BUGS
index 9690118..e658b05 100644 (file)
@@ -25,13 +25,14 @@ sub store_pdf {
   return if !$id || !$type;
 
   SL::File->save(
-    object_id   => $id,
-    object_type => $type,
-    mime_type   => 'application/pdf',
-    source      => 'created',
-    file_type   => 'document',
-    file_name   => $form->{attachment_filename},
-    file_path   => $form->{tmpfile},
+    object_id     => $id,
+    object_type   => $type,
+    mime_type     => 'application/pdf',
+    source        => 'created',
+    file_type     => 'document',
+    file_name     => $form->{attachment_filename},
+    file_path     => $form->{tmpfile},
+    print_variant => $form->{formname},
   );
 }
 
index da28bac..944a410 100644 (file)
@@ -305,7 +305,7 @@ sub produce_assembly {
   my $strict_wh = $::instance_conf->get_produce_assembly_same_warehouse ? $bin->warehouse : undef;
   if ($params{auto_allocate}) {
     Carp::croak("produce_assembly: can't have both allocations and auto_allocate") if $params{allocations};
-    $allocations = [ allocate_for_assembly(part => $part, qty => $qty, warehouse => $strict_wh) ];
+    $allocations = [ allocate_for_assembly(part => $part, qty => $qty, warehouse => $strict_wh, chargenumber => $params{chargenumber}) ];
   } else {
     Carp::croak("produce_assembly: need allocations or auto_allocate to produce something") if !$params{allocations};
     $allocations = $params{allocations};
index 0a0ef15..39a69fc 100644 (file)
@@ -3,6 +3,7 @@ package SL::Helper::Number;
 use strict;
 use Exporter qw(import);
 use List::Util qw(max min);
+use List::UtilsBy qw(rev_nsort_by);
 use Config;
 
 our @EXPORT_OK = qw(
index 553e812..9108a22 100644 (file)
@@ -64,11 +64,21 @@ sub get_print_options {
     ($form->{type} eq 'invoice') ? (
       opthash("invoice",             $form->{PD}{invoice},             $locale->text('Invoice')),
       opthash("proforma",            $form->{PD}{proforma},            $locale->text('Proforma Invoice')),
+      opthash("invoice_copy",        $form->{PD}{invoice_copy},        $locale->text('Invoice Copy')),
     ) : undef,
     ($form->{type} eq 'invoice' && $form->{storno}) ? (
       opthash("storno_invoice",      $form->{PD}{storno_invoice},      $locale->text('Storno Invoice')),
     ) : undef,
-    ($form->{type} =~ /_delivery_order$/) ? (
+    ($form->{type} eq 'invoice_for_advance_payment') ? (
+      opthash("invoice_for_advance_payment", $form->{PD}{invoice_for_advance_payment},      $locale->text('Invoice for Advance Payment')),
+    ) : undef,
+    ($form->{type} eq 'final_invoice') ? (
+      opthash("final_invoice", $form->{PD}{final_invoice},             $locale->text('Final Invoice')),
+    ) : undef,
+    ($form->{type} =~ /^supplier_delivery_order$/) ? (
+      opthash('supplier_delivery_order', $form->{PD}{supplier_delivery_order},  $locale->text('Supplier Delivery Order')),
+    ) : undef,
+    ($form->{type} =~ /(sales|purchase)_delivery_order$/) ? (
       opthash($form->{type},         $form->{PD}{$form->{type}},       $locale->text('Delivery Order')),
       opthash('pick_list',           $form->{PD}{pick_list},           $locale->text('Pick List')),
     ) : undef,
diff --git a/SL/Helper/QrBill.pm b/SL/Helper/QrBill.pm
new file mode 100644 (file)
index 0000000..c448eb2
--- /dev/null
@@ -0,0 +1,338 @@
+package SL::Helper::QrBill;
+
+use strict;
+use warnings;
+
+use Imager;
+use Imager::QRCode;
+
+my %Config = (
+  cross_file => 'image/CH-Kreuz_7mm.png',
+  out_file   => 'out.png',
+);
+
+sub new {
+  my $class = shift;
+
+  my $self = bless {}, $class;
+
+  $self->_init_check(@_);
+  $self->_init(@_);
+
+  return $self;
+}
+
+sub _init {
+  my $self = shift;
+  my ($biller_information, $biller_data, $payment_information, $invoice_recipient_data, $ref_nr_data) = @_;
+
+  $self->{data}{header} = [
+    'SPC',  # QRType
+    '0200', # Version
+     1,     # Coding Type
+  ];
+  $self->{data}{biller_information} = [
+    $biller_information->{iban},
+  ];
+  $self->{data}{biller_data} = [
+    $biller_data->{address_type},
+    $biller_data->{company},
+    $biller_data->{address_row1},
+    $biller_data->{address_row2},
+    '',
+    '',
+    $biller_data->{countrycode},
+  ];
+  $self->{data}{payment_information} = [
+    $payment_information->{amount},
+    $payment_information->{currency},
+  ];
+  $self->{data}{invoice_recipient_data} = [
+    $invoice_recipient_data->{address_type},
+    $invoice_recipient_data->{name},
+    $invoice_recipient_data->{address_row1},
+    $invoice_recipient_data->{address_row2},
+    '',
+    '',
+    $invoice_recipient_data->{countrycode},
+  ];
+  $self->{data}{ref_nr_data} = [
+    $ref_nr_data->{type},
+    $ref_nr_data->{ref_number},
+  ];
+  $self->{data}{additional_information} = [
+    '',
+    'EPD', # End Payment Data
+  ];
+}
+
+sub _init_check {
+  my $self = shift;
+  my ($biller_information, $biller_data, $payment_information, $invoice_recipient_data, $ref_nr_data) = @_;
+
+  my $check_re = sub {
+    my ($group, $href, $elem, $regex) = @_;
+    defined $href->{$elem} && $href->{$elem} =~ $regex
+      or die "field '$elem' in group '$group' not valid", "\n";
+  };
+
+  my $group = 'biller information';
+  $check_re->($group, $biller_information, 'iban', qr{^(?:CH|LI)[0-9a-zA-Z]{19}$});
+
+  $group = 'biller data';
+  $check_re->($group, $biller_data, 'address_type', qr{^[KS]$});
+  $check_re->($group, $biller_data, 'company', qr{^.{1,70}$});
+  $check_re->($group, $biller_data, 'address_row1', qr{^.{0,70}$});
+  $check_re->($group, $biller_data, 'address_row2', qr{^.{0,70}$});
+  $check_re->($group, $biller_data, 'countrycode', qr{^[A-Z]{2}$});
+
+  $group = 'payment information';
+  $check_re->($group, $payment_information, 'amount', qr{^(?:(?:0|[1-9][0-9]{0,8})\.[0-9]{2})?$});
+  $check_re->($group, $payment_information, 'currency', qr{^(?:CHF|EUR)$});
+
+  $group = 'invoice recipient data';
+  $check_re->($group, $invoice_recipient_data, 'address_type', qr{^[KS]$});
+  $check_re->($group, $invoice_recipient_data, 'name', qr{^.{1,70}$});
+  $check_re->($group, $invoice_recipient_data, 'address_row1', qr{^.{0,70}$});
+  $check_re->($group, $invoice_recipient_data, 'address_row2', qr{^.{0,70}$});
+  $check_re->($group, $invoice_recipient_data, 'countrycode', qr{^[A-Z]{2}$});
+
+  $group = 'reference number data';
+  my %ref_nr_regexes = (
+    QRR => qr{^\d{27}$},
+    NON => qr{^$},
+  );
+  $check_re->($group, $ref_nr_data, 'type', qr{^(?:QRR|SCOR|NON)$});
+  $check_re->($group, $ref_nr_data, 'ref_number', $ref_nr_regexes{$ref_nr_data->{type}});
+}
+
+sub generate {
+  my $self = shift;
+  my $out_file = $_[0] // $Config{out_file};
+
+  $self->{qrcode} = $self->_qrcode();
+  $self->{cross}  = $self->_cross();
+  $self->{img}    = $self->_plot();
+
+  $self->_paste();
+  $self->_write($out_file);
+}
+
+sub _qrcode {
+  my $self = shift;
+
+  return Imager::QRCode->new(
+    size   =>  4,
+    margin =>  0,
+    level  => 'M',
+  );
+}
+
+sub _cross {
+  my $self = shift;
+
+  my $cross = Imager->new();
+  $cross->read(file => $Config{cross_file}) or die $cross->errstr, "\n";
+
+  return $cross->scale(xpixels => 35, ypixels => 35, qtype => 'mixing');
+}
+
+sub _plot {
+  my $self = shift;
+
+  my @data = (
+    @{$self->{data}{header}},
+    @{$self->{data}{biller_information}},
+    @{$self->{data}{biller_data}},
+    ('') x 7, # for future use
+    @{$self->{data}{payment_information}},
+    @{$self->{data}{invoice_recipient_data}},
+    @{$self->{data}{ref_nr_data}},
+    @{$self->{data}{additional_information}},
+  );
+
+  foreach (@data) {
+    s/[\r\n]/ /g;
+    s/ {2,}/ /g;
+    s/^\s+//;
+    s/\s+$//;
+  }
+                  # CR + LF
+  my $text = join "\015\012", @data;
+
+  return $self->{qrcode}->plot($text);
+}
+
+sub _paste {
+  my $self = shift;
+
+  $self->{img}->paste(
+    src  => $self->{cross},
+    left => ($self->{img}->getwidth  / 2) - ($self->{cross}->getwidth  / 2),
+    top  => ($self->{img}->getheight / 2) - ($self->{cross}->getheight / 2),
+  );
+}
+
+sub _write {
+  my $self = shift;
+  my ($out_file) = @_;
+
+  $self->{img}->write(file => $out_file) or die $self->{img}->errstr, "\n";
+}
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Helper::QrBill - Helper methods for generating Swiss QR-Code
+
+=head1 SYNOPSIS
+
+     use SL::Helper::QrBill;
+
+     eval {
+       my $qr_image = SL::Helper::QrBill->new(
+         \%biller_information,
+         \%biller_data,
+         \%payment_information,
+         \%invoice_recipient_data,
+         \%ref_nr_data,
+       );
+       $qr_image->generate($out_file);
+     } or do {
+       local $_ = $@; chomp; my $error = $_;
+       $::form->error($::locale->text('QR-Image generation failed: ' . $error));
+     };
+
+=head1 DESCRIPTION
+
+This module generates the Swiss QR-Code with data provided to the constructor.
+
+=head1 METHODS
+
+=head2 C<new>
+
+Creates a new object. Expects five references to hashes as arguments.
+
+The hashes are structured as follows:
+
+=over 4
+
+=item C<%biller_information>
+
+Fields: iban.
+
+=over 4
+
+=item C<iban>
+
+Fixed length; 21 alphanumerical characters, only IBANs with CH- or LI-
+country code.
+
+=back
+
+=item C<%biller_data>
+
+Fields: address_type, company, address_row1, address_row2 and countrycode.
+
+=over 4
+
+=item C<address_type>
+
+Fixed length; 1-digit, alphanumerical. 'K' implemented only.
+
+=item C<company>
+
+Maximum of 70 characters, name (surname allowable) or company.
+
+=item C<address_row1>
+
+Maximum of 70 characters, street/nr.
+
+=item C<address_row2>
+
+Maximum of 70 characters, postal code/place.
+
+=item C<countrycode>
+
+2-digit country code according to ISO 3166-1.
+
+=back
+
+=item C<%payment_information>
+
+Fields: amount and currency.
+
+=over 4
+
+=item C<amount>
+
+Decimal, no leading zeroes, maximum of 12 digits (inclusive decimal
+separator and places). Only dot as decimal separator is permitted.
+
+=item C<currency>
+
+CHF/EUR.
+
+=back
+
+=item C<%invoice_recipient_data>
+
+Fields: address_type, name, address_row1, address_row2 and countrycode.
+
+=over 4
+
+=item C<address_type>
+
+Fixed length; 1-digit, alphanumerical. 'K' implemented only.
+
+=item C<name>
+
+Maximum of 70 characters, name (surname allowable) or company.
+
+=item C<address_row1>
+
+Maximum of 70 characters, street/nr.
+
+=item C<address_row2>
+
+Maximum of 70 characters, postal code/place.
+
+=item C<countrycode>
+
+2-digit country code according to ISO 3166-1.
+
+=back
+
+=item C<%ref_nr_data>
+
+Fields: type and ref_number.
+
+=over 4
+
+=item C<type>
+
+Maximum of 4 characters, alphanumerical. QRR/SCOR/NON.
+
+=item C<ref_number>
+
+QR-Reference: 27 characters, numerical; without Reference: empty.
+
+=back
+
+=back
+
+=head2 C<generate>
+
+Generates the QR-Code image. Accepts filename of image as argument.
+Defaults to C<out.png>.
+
+=head1 AUTHOR
+
+Steven Schubiger E<lt>stsc@refcnt.orgE<gt>
+
+=cut
index 383a3a3..6b878a9 100644 (file)
@@ -162,9 +162,9 @@ sub init_require_stock_out    { $::instance_conf->get_shipped_qty_require_stock_
 
 sub init_services_deliverable  {
   my ($self) = @_;
-  if ($::form->{type} =~ m/^sales_/ || $self->{objects}->[0]->{customer_id}) {
+  if (($::form->{type}//'') =~ m/^sales_/ || $self->{objects}->[0]->{customer_id}) {
     $::instance_conf->get_sales_delivery_order_check_service;
-  } elsif ($::form->{type} =~ m/^purchase_/ || $self->{objects}->[0]->{vendor_id}) {
+  } elsif (($::form->{type}//'') =~ m/^purchase_/ || $self->{objects}->[0]->{vendor_id}) {
     $::instance_conf->get_purchase_delivery_order_check_service;
   } else {
     croak "wrong call, no customer or vendor object referenced";
index 56ea12e..e79991c 100644 (file)
@@ -39,7 +39,7 @@ my @mappings = (
   [ 'LTR', qr{^(?:l|liter|litre)$}i ],
 
   # miscellaneous
-  [ 'C62', qr{^(?:stck|stück|pieces?|pc|psch|pauschal)$}i ],
+  [ 'C62', qr{^(?:stck|stück|pieces?|pc|psch|pauschal|licenses?|lizenz(?:en)?)$}i ],
 );
 
 sub map_name_to_code {
diff --git a/SL/Helper/UserPreferences/DisplayPreferences.pm b/SL/Helper/UserPreferences/DisplayPreferences.pm
new file mode 100644 (file)
index 0000000..f3bcae3
--- /dev/null
@@ -0,0 +1,66 @@
+package SL::Helper::UserPreferences::DisplayPreferences;
+
+use strict;
+use parent qw(Rose::Object);
+
+use SL::Helper::UserPreferences;
+
+use Rose::Object::MakeMethods::Generic (
+  'scalar --get_set_init' => [ qw(user_prefs) ],
+);
+
+sub get_longdescription_dialog_size_percentage {
+  $_[0]->user_prefs->get('longdescription_dialog_size_percentage');
+}
+
+sub store_longdescription_dialog_size_percentage {
+  $_[0]->user_prefs->store('longdescription_dialog_size_percentage', $_[1]);
+}
+
+sub init_user_prefs {
+  SL::Helper::UserPreferences->new(
+    namespace => $_[0]->namespace,
+  )
+}
+
+# read only stuff
+sub namespace     { 'DisplayPreferences' }
+sub version       { 1 }
+
+1;
+
+__END__
+
+=pod
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Helper::UserPreferences::DisplayPreferences - preferences intended
+to store user settings for various display settings.
+
+=head1 SYNOPSIS
+
+  use SL::Helper::UserPreferences::DisplayPreferences;
+  my $prefs = SL::Helper::UserPreferences::DisplayPreferences->new();
+
+  $prefs->store_use_duration(1);
+  my $value = $prefs->get_longdescription_dialog_size_percentage;
+
+=head1 DESCRIPTION
+
+This module manages storing the user's choise for settings for
+various display settings.
+For now the preferred procentual size of the edit-dialog for longdescriptions
+of positions can be stored.
+
+=head1 BUGS
+
+None yet :)
+
+=head1 AUTHOR
+
+Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
+
+=cut
index f36ca04..2a94607 100644 (file)
--- a/SL/IC.pm
+++ b/SL/IC.pm
@@ -524,6 +524,8 @@ sub all_parts {
 
   # simple search for assemblies by items used in assemblies
   if ($form->{bom} eq '2' && $form->{l_assembly}) {
+    # assembly_qty is the column name
+    $form->{l_assembly_qty} = 1;
     # nuke where clause and bind vars
     $where_clause = ' 1=1 AND p.id in (SELECT id from assembly where parts_id IN ' .
                     ' (select id from parts where 1=1';
@@ -563,7 +565,7 @@ sub all_parts {
   my @assemblies;
   if ($form->{l_assembly} && $form->{bom}) {
     $query =
-      qq|SELECT p.id, p.partnumber, p.description, a.qty AS onhand,
+      qq|SELECT p.id, p.partnumber, p.description, a.qty AS assembly_qty,
            p.unit, p.notes, p.itime::DATE as insertdate,
            p.sellprice, p.listprice, p.lastcost,
            p.rop, p.weight,
@@ -734,7 +736,7 @@ sub retrieve_accounts {
 
   # transdate madness.
   my $transdate = "";
-  if (($form->{type} eq "invoice") or ($form->{type} eq "credit_note") or ($form->{script} eq 'ir.pl')) {
+  if ( (any {$form->{type} eq $_} qw(invoice credit_note invoice_for_advance_payment final_invoice)) or ($form->{script} eq 'ir.pl') ) {
     # use deliverydate for sales and purchase invoice, if it exists
     # also use deliverydate for credit notes
     $transdate = $form->{tax_point} || $form->{deliverydate} || $form->{invdate};
index 7cf8008..fdc70ab 100644 (file)
--- a/SL/IS.pm
+++ b/SL/IS.pm
@@ -35,7 +35,8 @@
 
 package IS;
 
-use List::Util qw(max);
+use List::Util qw(max sum0);
+use List::MoreUtils qw(any);
 
 use Carp;
 use SL::AM;
@@ -51,6 +52,7 @@ use SL::MoreCommon;
 use SL::IC;
 use SL::IO;
 use SL::TransNumber;
+use SL::DB::Chart;
 use SL::DB::Default;
 use SL::DB::Draft;
 use SL::DB::Tax;
@@ -175,7 +177,13 @@ sub invoice_details {
 
   my @payment_arrays = qw(payment paymentaccount paymentdate paymentsource paymentmemo);
 
-  map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays, @payment_arrays, @prepared_arrays);
+  my @invoices_for_advance_payment_arrays = qw(iap_invnumber iap_transdate
+                                               iap_amount iap_amount_nofmt
+                                               iap_taxamount iap_taxamount_nofmt
+                                               iap_open_amount iap_open_amount_nofmt
+                                               iap_netamount);
+
+  map { $form->{TEMPLATE_ARRAYS}->{$_} = [] } (@arrays, @tax_arrays, @payment_arrays, @prepared_arrays, @invoices_for_advance_payment_arrays);
 
   my $totalweight = 0;
   foreach $item (sort { $a->[1] cmp $b->[1] } @partsgroup) {
@@ -560,6 +568,11 @@ sub invoice_details {
     2
   );
 
+  $form->{rounding_nofmt} = $form->{rounding};
+  $form->{total_nofmt}    = $form->{total};
+  $form->{invtotal_nofmt} = $form->{invtotal};
+  $form->{paid_nofmt}     = $form->{paid};
+
   $form->{rounding} = $form->format_amount($myconfig, $form->{rounding}, 2);
   $form->{total}    = $form->format_amount($myconfig, $form->{invtotal} - $form->{paid}, 2);
   $form->{invtotal} = $form->format_amount($myconfig, $form->{invtotal}, 2);
@@ -574,6 +587,39 @@ sub invoice_details {
   $form->{username} = $myconfig->{name};
   $form->{$_} = $form->format_amount($myconfig, $form->{$_}, 2) for @separate_totals;
 
+  my $id_for_iap = $form->{convert_from_oe_ids} || $form->{convert_from_ar_ids} || $form->{id};
+  my $from_order = !!$form->{convert_from_oe_ids};
+  foreach my $invoice_for_advance_payment (@{$self->_get_invoices_for_advance_payment($id_for_iap, $from_order)}) {
+    # Collect VAT of invoices for advance payment.
+    # Set sellprices to fxsellprices for items, because
+    # the PriceTaxCalculator sets fxsellprice from sellprice before calculating.
+    $_->sellprice($_->fxsellprice) for @{$invoice_for_advance_payment->items};
+    my %pat       = $invoice_for_advance_payment->calculate_prices_and_taxes;
+    my $taxamount = sum0 values %{ $pat{taxes_by_tax_id} };
+
+    push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_$_"} },                $invoice_for_advance_payment->$_) for qw(invnumber transdate);
+    push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_amount_nofmt"} },      $invoice_for_advance_payment->amount);
+    push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_amount"} },            $invoice_for_advance_payment->amount_as_number);
+    push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_netamount"} },         $invoice_for_advance_payment->netamount_as_number);
+    push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_taxamount_nofmt"} },   $taxamount);
+    push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_taxamount"} },         $form->format_amount($myconfig, $taxamount, 2));
+
+    my $open_amount = $form->round_amount($invoice_for_advance_payment->open_amount, 2);
+    push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_open_amount_nofmt"} }, $open_amount);
+    push(@{ $form->{TEMPLATE_ARRAYS}->{"iap_open_amount"} },       $form->format_amount($myconfig, $open_amount, 2));
+
+    $form->{iap_amount_nofmt}      += $invoice_for_advance_payment->amount;
+    $form->{iap_taxamount_nofmt}   += $taxamount;
+    $form->{iap_open_amount_nofmt} += $open_amount;
+    $form->{iap_existing}           = 1;
+  }
+  $form->{iap_amount}      = $form->format_amount($myconfig, $form->{iap_amount_nofmt},      2);
+  $form->{iap_taxamount}   = $form->format_amount($myconfig, $form->{iap_taxamount_nofmt},   2);
+  $form->{iap_open_amount} = $form->format_amount($myconfig, $form->{iap_open_amount_nofmt}, 2);
+
+  $form->{iap_final_amount_nofmt} = $form->{invtotal_nofmt} - $form->{iap_amount_nofmt};
+  $form->{iap_final_amount}       = $form->format_amount($myconfig, $form->{iap_final_amount_nofmt}, 2);
+
   $main::lxdebug->leave_sub();
 }
 
@@ -714,6 +760,8 @@ sub _post_invoice {
 
   my $all_units = AM->retrieve_units($myconfig, $form);
 
+  my $already_booked = !!$form->{id};
+
   if (!$payments_only) {
     if ($form->{storno}) {
       _delete_transfers($dbh, $form, $form->{storno_id});
@@ -1039,6 +1087,105 @@ SQL
   # entsprechend auch beim Bestimmen des Steuerschlüssels in Taxkey.pm berücksichtigen
   my $taxdate = $form->{tax_point} ||$form->{deliverydate} || $form->{invdate};
 
+  # Sanity checks for invoices for advance payment and final invoices
+  my $advance_payment_clearing_chart;
+  if (any { $_ eq $form->{type} } qw(invoice_for_advance_payment final_invoice)) {
+    $advance_payment_clearing_chart = SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_clearing_chart_id)->load;
+    die "No Clearing Chart for Advance Payment" unless ref $advance_payment_clearing_chart eq 'SL::DB::Chart';
+
+    my @current_taxaccounts = (split(/ /, $form->{taxaccounts}));
+    die 'Wrong call: Cannot post invoice for advance payment or final invoice with more than one tax' if (scalar @current_taxaccounts > 1);
+
+    my @trans_ids = keys %{ $form->{amount} };
+    if (scalar @trans_ids > 1) {
+      require Data::Dumper;
+      die "Invalid state for advance payment more than one trans_id " . Dumper($form->{amount});
+    }
+  }
+
+  my $iap_amounts;
+  if ($form->{type} eq 'final_invoice') {
+    my $id_for_iap = $form->{convert_from_oe_ids} || $form->{convert_from_ar_ids} || $form->{id};
+    my $from_order = !!$form->{convert_from_oe_ids};
+    my $invoices_for_advance_payment = $self->_get_invoices_for_advance_payment($id_for_iap, $from_order);
+    if (scalar @$invoices_for_advance_payment > 0) {
+      # reverse booking for invoices for advance payment
+      foreach my $invoice_for_advance_payment (@$invoices_for_advance_payment) {
+        # delete ?
+        # --> is implemented below (bookings are marked in memo field)
+        #
+        # TODO: helper table acc_trans_advance_payment
+        # trans_id for final invoice connects to acc_trans_id here
+        # my $booking = SL::DB::AccTrans->new( ...)
+        # --> helper table not nessessary because of mark in memo field
+        #
+        # TODO: If final_invoice change (delete storno) delete all connectin acc_trans entries, if
+        # period is not closed
+        # --> no problem because gldate of reverse booking is date of final invoice
+        #     if deletion of final invoice is allowed, reverting bookings in invoices
+        #     for advance payment are allowed, too.
+        # $booking->id, $self->id in helper table
+        if (!$already_booked) {
+          # move all netamount to correct transfer chart (19% or 7%)
+          my %inv_calc = $invoice_for_advance_payment->calculate_prices_and_taxes();
+          my @trans_ids = keys %{ $inv_calc{amounts} };
+          die "Invalid state for advance payment invoice,more than one trans_id" if (scalar @trans_ids > 1);
+          my $entry = delete $inv_calc{amounts}{$trans_ids[0]};
+          my $tax;
+          if ($entry->{tax_id}) {
+            $tax = SL::DB::Manager::Tax->find_by(id => $entry->{tax_id}); # || die "Can't find tax with id " . $entry->{tax_id};
+          }
+          # no tax, no prob
+          if ($tax and $tax->rate != 0) {
+            my $transfer_chart = $tax->taxkey == 2 ? SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_taxable_7_id)->load
+                              :  $tax->taxkey == 3 ? SL::DB::Chart->new(id => $::instance_conf->get_advance_payment_taxable_19_id)->load
+                              :  undef;
+            die "No Transfer Chart for Advance Payment" unless ref $transfer_chart eq 'SL::DB::Chart';
+            $form->{amount}->{$invoice_for_advance_payment->id}->{$transfer_chart->accno} = -1 * $invoice_for_advance_payment->netamount;
+            $form->{memo}  ->{$invoice_for_advance_payment->id}->{$transfer_chart->accno} = 'reverse booking by final invoice';
+            # AR
+            $form->{amount}->{$invoice_for_advance_payment->id}->{$form->{AR}} = $invoice_for_advance_payment->netamount;
+            $form->{memo}  ->{$invoice_for_advance_payment->id}->{$form->{AR}} = 'reverse booking by final invoice';
+          }
+        }
+
+        # VAT for invoices for advance payment is booked on payment of these. So do not book this VAT for final invoice.
+        # And book the amount of the invoices for advance payment with taxkey 0 (see below).
+        # Collect amounts and VAT of invoices for advance payment.
+
+        # Set sellprices to fxsellprices for items, because
+        # the PriceTaxCalculator sets fxsellprice from sellprice before calculating.
+        $_->sellprice($_->fxsellprice) for @{$invoice_for_advance_payment->items};
+        my %pat = $invoice_for_advance_payment->calculate_prices_and_taxes;
+
+        foreach my $tax_chart_id (keys %{ $pat{taxes_by_chart_id} }) {
+          my $tax_accno = SL::DB::Chart->load_cached($tax_chart_id)->accno;
+          $form->{amount}{ $form->{id} }{$tax_accno}  -= $pat{taxes_by_chart_id}->{$tax_chart_id};
+          $form->{amount}{ $form->{id} }{$form->{AR}} += $pat{taxes_by_chart_id}->{$tax_chart_id};
+        }
+
+        foreach my $amount_chart_id (keys %{ $pat{amounts} }) {
+          my $amount_accno = SL::DB::Chart->load_cached($amount_chart_id)->accno;
+          $iap_amounts->{$amount_accno}                 += $pat{amounts}->{$amount_chart_id}->{amount};
+          $form->{amount}{ $form->{id} }{$amount_accno} -= $pat{amounts}->{$amount_chart_id}->{amount};
+        }
+      }
+    }
+  }
+
+  if ($form->{type} eq 'invoice_for_advance_payment') {
+    # get gross and move to clearing chart - delete everything else
+    # 1. gross
+    my $gross = $form->{amount}{ $form->{id} }{$form->{AR}};
+    # 2. destroy
+    undef $form->{amount}{ $form->{id} };
+    # 3. rebuild
+    $form->{amount}{ $form->{id} }{$form->{AR}}            = $gross;
+    $form->{amount}{ $form->{id} }{$advance_payment_clearing_chart->accno} = $gross * -1;
+    # 4. no cogs, hopefully not commonly used at all
+    undef $form->{amount_cogs};
+  }
+
   foreach my $trans_id (keys %{ $form->{amount_cogs} }) {
     foreach my $accno (keys %{ $form->{amount_cogs}{$trans_id} }) {
       next unless ($form->{expense_inventory} =~ /\Q$accno\E/);
@@ -1076,7 +1223,7 @@ SQL
 
       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
         $query =
-          qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
+          qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link, memo)
              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
                      (SELECT tax_id
                       FROM taxkeys
@@ -1093,8 +1240,9 @@ SQL
                       AND startdate <= ?
                       ORDER BY startdate DESC LIMIT 1),
                      ?,
-                     (SELECT link FROM chart WHERE accno = ?))|;
-        @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno);
+                     (SELECT link FROM chart WHERE accno = ?),
+                     ?)|;
+        @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno, $form->{memo}{$trans_id}{$accno});
         do_query($form, $dbh, $query, @values);
         $form->{amount}{$trans_id}{$accno} = 0;
       }
@@ -1105,7 +1253,7 @@ SQL
 
       if (!$payments_only && ($form->{amount}{$trans_id}{$accno} != 0)) {
         $query =
-          qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
+          qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link, memo)
              VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
                      (SELECT tax_id
                       FROM taxkeys
@@ -1122,8 +1270,9 @@ SQL
                       AND startdate <= ?
                       ORDER BY startdate DESC LIMIT 1),
                      ?,
-                     (SELECT link FROM chart WHERE accno = ?))|;
-        @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno);
+                     (SELECT link FROM chart WHERE accno = ?),
+                     ?)|;
+        @values = (conv_i($trans_id), $accno, $form->{amount}{$trans_id}{$accno}, conv_date($form->{invdate}), $accno, conv_date($taxdate), $accno, conv_date($taxdate), conv_i($project_id), $accno,$form->{memo}{$trans_id}{$accno});
         do_query($form, $dbh, $query, @values);
       }
     }
@@ -1137,6 +1286,17 @@ SQL
     }
   }
 
+  # Book the amount of the invoices for advance payment with taxkey 0 (see below).
+  if ($form->{type} eq 'final_invoice' && $iap_amounts) {
+    foreach my $accno (keys %$iap_amounts) {
+      $query =
+        qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, tax_id, taxkey, project_id, chart_link)
+        VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, (SELECT id FROM tax WHERE taxkey=0), 0, ?, (SELECT link FROM chart WHERE accno = ?))|;
+      @values = (conv_i($form->{id}), $accno, $iap_amounts->{$accno}, conv_date($form->{invdate}), conv_i($project_id), $accno);
+      do_query($form, $dbh, $query, @values);
+    }
+  }
+
   # deduct payment differences from diff
   for my $i (1 .. $form->{paidaccounts}) {
     if ($form->{"paid_$i"} != 0) {
@@ -1318,12 +1478,12 @@ SQL
                 shipvia     = ?,                    notes         = ?, intnotes      = ?,
                 currency_id = (SELECT id FROM currencies WHERE name = ?),
                 department_id = ?, payment_id    = ?, taxincluded   = ?,
-                type        = ?, language_id   = ?, taxzone_id    = ?, shipto_id     = ?,
+                type        = ?, language_id   = ?, taxzone_id    = ?, shipto_id     = ?, billing_address_id = ?,
                 employee_id = ?, salesman_id   = ?, storno_id     = ?, storno        = ?,
                 cp_id       = ?, marge_total   = ?, marge_percent = ?,
                 globalproject_id               = ?, delivery_customer_id             = ?,
                 transaction_description        = ?, delivery_vendor_id               = ?,
-                donumber    = ?, invnumber_for_credit_note = ?,        direct_debit  = ?,
+                donumber    = ?, invnumber_for_credit_note = ?,        direct_debit  = ?, qrbill_without_amount = ?,
                 delivery_term_id = ?
               WHERE id = ?|;
   @values = (          $form->{"invnumber"},           $form->{"ordnumber"},             $form->{"quonumber"},          $form->{"cusordnumber"},
@@ -1332,12 +1492,12 @@ SQL
              conv_date($form->{"duedate"}),  conv_date($form->{"deliverydate"}),    '1',                                $form->{"shippingpoint"},
                        $form->{"shipvia"},                                $restricter->process($form->{"notes"}),       $form->{"intnotes"},
                        $form->{"currency"},     conv_i($form->{"department_id"}), conv_i($form->{"payment_id"}),        $form->{"taxincluded"} ? 't' : 'f',
-                       $form->{"type"},         conv_i($form->{"language_id"}),   conv_i($form->{"taxzone_id"}), conv_i($form->{"shipto_id"}),
+                       $form->{"type"},         conv_i($form->{"language_id"}),   conv_i($form->{"taxzone_id"}), conv_i($form->{"shipto_id"}), conv_i($form->{billing_address_id}),
                 conv_i($form->{"employee_id"}), conv_i($form->{"salesman_id"}),   conv_i($form->{storno_id}),           $form->{"storno"} ? 't' : 'f',
                 conv_i($form->{"cp_id"}),            1 * $form->{marge_total} ,      1 * $form->{marge_percent},
                 conv_i($form->{"globalproject_id"}),                              conv_i($form->{"delivery_customer_id"}),
                        $form->{transaction_description},                          conv_i($form->{"delivery_vendor_id"}),
-                       $form->{"donumber"}, $form->{"invnumber_for_credit_note"},        $form->{direct_debit} ? 't' : 'f',
+                       $form->{"donumber"}, $form->{"invnumber_for_credit_note"},        $form->{direct_debit} ? 't' : 'f', $form->{qrbill_without_amount} ? 't' : 'f',
                 conv_i($form->{delivery_term_id}),
                 conv_i($form->{"id"}));
   do_query($form, $dbh, $query, @values);
@@ -1459,6 +1619,50 @@ SQL
   return 1;
 }
 
+sub _get_invoices_for_advance_payment {
+  my ($self, $id, $id_is_from_order) = @_;
+
+  return [] if !$id;
+
+  # Search all related invoices for advance payment.
+  # Case 1:
+  # (order) -> invoice for adv. payment 1 -> invoice for adv. payment 2 -> invoice for adv. payment 3 -> final invoice
+  #
+  # Case 2:
+  # order -> invoice for adv. payment 1
+  #   | |`-> invoice for adv. payment 2
+  #   | `--> invoice for adv. payment 3
+  #   `----> final invoice
+  #
+  # The id is currently that from the last invoice for adv. payment (3 in this example),
+  # that from the final invoice or that from the order.
+
+  my $invoice_obj;
+  my $order_obj;
+  my $links;
+
+  if (!$id_is_from_order) {
+    $invoice_obj = SL::DB::Invoice->load_cached($id*1);
+    $links       = $invoice_obj->linked_records(direction => 'from', from => ['Order']);
+    $order_obj   = $links->[0];
+  } else {
+    $order_obj   = SL::DB::Order->load_cached($id*1);
+  }
+
+  if ($order_obj) {
+    $links        = $order_obj  ->linked_records(direction => 'to',   to => ['Invoice']);
+  } else {
+    $links        = $invoice_obj->linked_records(direction => 'from', from => ['Invoice'], recursive => 1);
+  }
+
+  my @related_invoices = grep {'SL::DB::Invoice' eq ref $_ && "invoice_for_advance_payment" eq $_->type} @$links;
+
+  push @related_invoices, $invoice_obj if !$order_obj && "invoice_for_advance_payment" eq $invoice_obj->type;
+
+  return \@related_invoices;
+}
+
+
 sub transfer_out {
   $::lxdebug->enter_sub;
 
@@ -1965,6 +2169,18 @@ sub _delete_invoice {
     do_query($form, $dbh, qq|UPDATE ar SET storno = 'f', paid = 0 WHERE id = ?|, $invoice_id);
   }
 
+  # if we delete a final invoice, the reverse bookings for the clearing account in the invoice for advance payment
+  # must be deleted as well
+  my $invoices_for_advance_payment = $self->_get_invoices_for_advance_payment($form->{id});
+
+  # Todo: allow only if invoice for advance payment is not paid.
+  # die if any { $_->paid } for @$invoices_for_advance_payment;
+  my @trans_ids_to_consider        = map { $_->id } @$invoices_for_advance_payment;
+  if (scalar @trans_ids_to_consider) {
+    my $query = sprintf 'DELETE FROM acc_trans WHERE memo LIKE ? AND trans_id IN (%s)', join ', ', ("?") x scalar @trans_ids_to_consider;
+    do_query($form, $dbh, $query, 'reverse booking by final invoice', @trans_ids_to_consider);
+  }
+
   # delete spool files
   my @spoolfiles = selectall_array_query($form, $dbh, qq|SELECT spoolfile FROM status WHERE trans_id = ?|, @values);
 
@@ -2030,11 +2246,12 @@ sub _retrieve_invoice {
            a.transdate AS invdate, a.deliverydate, a.tax_point, a.paid, a.storno, a.storno_id, a.gldate,
            a.shippingpoint, a.shipvia, a.notes, a.intnotes, a.taxzone_id,
            a.duedate, a.taxincluded, (SELECT cu.name FROM currencies cu WHERE cu.id=a.currency_id) AS currency, a.shipto_id, a.cp_id,
+           a.billing_address_id,
            a.employee_id, a.salesman_id, a.payment_id,
            a.mtime, a.itime,
            a.language_id, a.delivery_customer_id, a.delivery_vendor_id, a.type,
            a.transaction_description, a.donumber, a.invnumber_for_credit_note,
-           a.marge_total, a.marge_percent, a.direct_debit, a.delivery_term_id,
+           a.marge_total, a.marge_percent, a.direct_debit, a.qrbill_without_amount, a.delivery_term_id,
            dc.dunning_description,
            e.name AS employee
          FROM ar a
@@ -2218,6 +2435,10 @@ sub get_customer {
          c.street, c.zipcode, c.city, c.country,
          c.notes AS intnotes, c.pricegroup_id as customer_pricegroup_id, c.taxzone_id, c.salesman_id, cu.name AS curr,
          c.taxincluded_checked, c.direct_debit,
+         (SELECT aba.id
+          FROM additional_billing_addresses aba
+          WHERE aba.default_address
+          LIMIT 1) AS default_billing_address_id,
          b.discount AS tradediscount, b.description AS business
        FROM customer c
        LEFT JOIN business b ON (b.id = c.business_id)
index 1109897..acb34c5 100644 (file)
@@ -43,6 +43,9 @@ BEGIN {
   { name => 'HTML::Parser',                        url => 'http://search.cpan.org/~gaas/',      debian => 'libhtml-parser-perl', },
   { name => 'HTML::Restrict',                      url => 'http://search.cpan.org/~oalders/',   debian => 'libhtml-restrict-perl'},
   { name => "Image::Info",                         url => "http://search.cpan.org/~srezic/",    debian => 'libimage-info-perl' },
+  { name => "Imager",                              url => "http://search.cpan.org/~tonyc/",     debian => 'libimager-perl' },
+  { name => "Imager::QRCode",                      url => "http://search.cpan.org/~kurihara/",  debian => 'libimager-qrcode-perl' },
+  { name => "IPC::Run",                            url => "https://metacpan.org/pod/IPC::Run",  debian => 'libipc-run-perl' },
   { name => "JSON",                                url => "http://search.cpan.org/~makamaka",   debian => 'libjson-perl' },
   { name => "List::MoreUtils", version => '0.30',  url => "http://search.cpan.org/~vparseval/", debian => 'liblist-moreutils-perl' },
   { name => "List::UtilsBy",   version => '0.09',  url => "http://search.cpan.org/~pevans/",    debian => 'liblist-utilsby-perl' },
@@ -53,6 +56,7 @@ BEGIN {
   { name => "PBKDF2::Tiny",    version => '0.005', url => "http://search.cpan.org/~dagolden/",  debian => 'libpbkdf2-tiny-perl' },
   { name => "PDF::API2",       version => '2.000', url => "http://search.cpan.org/~areibens/",  debian => 'libpdf-api2-perl' },
   { name => "Regexp::IPv6",    version => '0.03',  url => "http://search.cpan.org/~salva/",     debian => 'libregexp-ipv6-perl' },
+  { name => "REST::Client",                        url => "https://metacpan.org/pod/REST::Client", debian => 'librest-client-perl' },
   { name => "Rose::Object",                        url => "http://search.cpan.org/~jsiracusa/", debian => 'librose-object-perl' },
   { name => "Rose::DB",                            url => "http://search.cpan.org/~jsiracusa/", debian => 'librose-db-perl' },
   { name => "Rose::DB::Object", version => 0.788,  url => "http://search.cpan.org/~jsiracusa/", debian => 'librose-db-object-perl' },
@@ -82,6 +86,7 @@ BEGIN {
 @developer_modules = (
   { name => "DBIx::Log4perl",                      url => "http://search.cpan.org/~mjevans/", },
   { name => "Devel::REPL",                         url => "http://search.cpan.org/~doy/",       debian => 'libdevel-repl-perl' },
+  { name => "Term::ReadLine::Gnu",                 url => "http://search.cpan.org/~hayashi/",   debian => 'libterm-readline-gnu-perl' },
   { name => "Log::Log4perl",                       url => "http://search.cpan.org/~mschilli/",  debian => 'liblog-log4perl-perl' },
   { name => "LWP::Simple",                         url => "http://search.cpan.org/~gaas/",      debian => 'libwww-perl', dist_name => 'libwww-perl' },
   { name => "Moose::Role",                         url => "http://search.cpan.org/~doy/",       debian => 'libmoose-perl' },
index a408b03..f242120 100644 (file)
@@ -29,11 +29,13 @@ use Encode;
 use File::MimeInfo::Magic;
 use File::Slurp;
 use List::UtilsBy qw(bundle_by);
+use List::Util qw(sum);
 
 use SL::Common;
 use SL::DB::EmailJournal;
 use SL::DB::EmailJournalAttachment;
 use SL::DB::Employee;
+use SL::Locale::String qw(t8);
 use SL::Template;
 use SL::Version;
 
@@ -121,8 +123,21 @@ sub _create_address_headers {
     next if !$self->{$item};
 
     my @header_addresses;
+    my @addresses = Email::Address->parse($self->{$item});
+
+    # if either no address was parsed or
+    # there are more than 3 characters per parsed email extra, assume the the user has entered bunk
+    if (!@addresses) {
+       die t8('"#1" seems to be a faulty list of email addresses. No addresses could be extracted.',
+         $self->{$item},
+       );
+    } elsif ((length($self->{$item}) - sum map { length $_->original } @addresses) / @addresses > 3) {
+       die t8('"#1" seems to be a faulty list of email addresses. After extracing addresses (#2) too many characters are left.',
+         $self->{$item}, join ', ', map { $_->original } @addresses,
+       );
+    }
 
-    foreach my $addr_obj (Email::Address->parse($self->{$item})) {
+    foreach my $addr_obj (@addresses) {
       push @{ $self->{addresses}->{$item} }, $addr_obj->address;
       next if $self->{driver}->keep_from_header($item);
 
index 6b48312..4ce1b10 100644 (file)
--- a/SL/OE.pm
+++ b/SL/OE.pm
@@ -44,6 +44,7 @@ use SL::DB::Order;
 use SL::DB::PeriodicInvoicesConfig;
 use SL::DB::Project;
 use SL::DB::ProjectType;
+use SL::DB::RequirementSpecOrder;
 use SL::DB::Status;
 use SL::DB::Tax;
 use SL::DBUtils;
@@ -115,6 +116,13 @@ sub transactions {
     }
   }
 
+  my ($phone_notes_columns, $phone_notes_join);
+  $form->{phone_notes} = trim($form->{phone_notes});
+  if ($form->{phone_notes}) {
+    $phone_notes_columns = qq| , phone_notes.subject AS phone_notes_subject, phone_notes.body AS phone_notes_body |;
+    $phone_notes_join    = qq| JOIN notes phone_notes ON (o.id = phone_notes.trans_id AND phone_notes.trans_module LIKE 'oe') |;
+  }
+
   $query =
     qq|SELECT o.id, o.ordnumber, o.transdate, o.reqdate, | .
     qq|  o.amount, ct.${vc}number, ct.name, o.netamount, o.${vc}_id, o.globalproject_id, | .
@@ -132,6 +140,7 @@ sub transactions {
     qq|  ct.${vc}number AS vcnumber, ct.country, ct.ustid, ct.business_id,  | .
     qq|  tz.description AS taxzone | .
     $periodic_invoices_columns .
+    $phone_notes_columns .
     qq|  , o.order_probability, o.expected_billing_date, (o.netamount * o.order_probability / 100) AS expected_netamount | .
     qq|FROM oe o | .
     qq|JOIN $vc ct ON (o.${vc}_id = ct.id) | .
@@ -145,6 +154,7 @@ sub transactions {
     qq|LEFT JOIN tax_zones tz ON (o.taxzone_id = tz.id) | .
     qq|LEFT JOIN department   ON (o.department_id = department.id) | .
     qq|$periodic_invoices_joins | .
+    $phone_notes_join .
     qq|WHERE (o.quotation = ?) |;
   push(@values, $quotation);
 
@@ -191,7 +201,8 @@ SQL
     push(@values, (like($form->{"cp_name"}))x2);
   }
 
-  if ( !(($vc eq 'customer' && $main::auth->assert('sales_all_edit', 1)) || ($vc eq 'vendor' && $main::auth->assert('purchase_all_edit', 1))) ) {
+  if ( !(    ($vc eq 'customer' && ($main::auth->assert('sales_all_edit',    1) || $main::auth->assert('sales_order_view',    1)))
+          || ($vc eq 'vendor'   && ($main::auth->assert('purchase_all_edit', 1) || $main::auth->assert('purchase_order_view', 1))) ) ) {
     $query .= " AND o.employee_id = (select id from employee where login= ?)";
     push @values, $::myconfig{login};
   }
@@ -302,6 +313,54 @@ SQL
     push(@values, like($form->{intnotes}));
   }
 
+  if ($form->{phone_notes}) {
+    $query .= qq| AND (phone_notes.subject ILIKE ? OR phone_notes.body ILIKE ?)|;
+    push(@values, like($form->{phone_notes}), like($form->{phone_notes}));
+  }
+
+  $form->{fulltext} = trim($form->{fulltext});
+  if ($form->{fulltext}) {
+    my @fulltext_fields = qw(o.notes
+                             o.intnotes
+                             o.shippingpoint
+                             o.shipvia
+                             o.transaction_description
+                             o.quonumber
+                             o.ordnumber
+                             o.cusordnumber);
+    $query .= ' AND (';
+    $query .= join ' ILIKE ? OR ', @fulltext_fields;
+    $query .= ' ILIKE ?';
+
+    $query .= <<SQL;
+      OR EXISTS (
+        SELECT files.id FROM files LEFT JOIN file_full_texts ON (file_full_texts.file_id = files.id)
+          WHERE files.object_id = o.id AND files.object_type = 'sales_order'
+            AND file_full_texts.full_text ILIKE ?)
+SQL
+
+    $query .= <<SQL;
+      OR EXISTS (
+        SELECT notes.id FROM notes
+          WHERE notes.trans_id = o.id AND notes.trans_module LIKE 'oe'
+            AND (notes.subject ILIKE ? OR notes.body ILIKE ?))
+SQL
+
+    $query .= <<SQL;
+      OR EXISTS (
+        SELECT follow_up_links.id FROM follow_up_links
+          WHERE follow_up_links.trans_id = o.id AND trans_type = 'sales_order'
+            AND EXISTS (
+              SELECT notes.id FROM notes
+                WHERE trans_module LIKE 'fu' AND trans_id = follow_up_links.follow_up_id
+                  AND (notes.subject ILIKE ? OR notes.body ILIKE ?)))
+SQL
+
+    $query .= ')';
+
+    push(@values, like($form->{fulltext})) for 1 .. (scalar @fulltext_fields) + 5;
+  }
+
   if ($form->{parts_partnumber}) {
     $query .= <<SQL;
       AND EXISTS (
@@ -479,6 +538,7 @@ sub _save {
   my $number_field         = $form->{type} =~ m{order} ? 'ordnumber' : 'quonumber';
   my $trans_number         = SL::TransNumber->new(type => $form->{type}, dbh => $dbh, number => $form->{$number_field}, id => $form->{id});
   $form->{$number_field} ||= $trans_number->create_unique; # set $form->{ordnumber} or $form->{quonumber}
+  my $is_new               = !$form->{id};
 
   if ($form->{id}) {
     $query = qq|DELETE FROM custom_variables
@@ -753,7 +813,7 @@ SQL
          customer_id = ?, amount = ?, netamount = ?, reqdate = ?, tax_point = ?, taxincluded = ?,
          shippingpoint = ?, shipvia = ?, notes = ?, intnotes = ?, currency_id = (SELECT id FROM currencies WHERE name=?), closed = ?,
          delivered = ?, proforma = ?, quotation = ?, department_id = ?, language_id = ?,
-         taxzone_id = ?, shipto_id = ?, payment_id = ?, delivery_vendor_id = ?, delivery_customer_id = ?,delivery_term_id = ?,
+         taxzone_id = ?, shipto_id = ?, billing_address_id = ?, payment_id = ?, delivery_vendor_id = ?, delivery_customer_id = ?,delivery_term_id = ?,
          globalproject_id = ?, employee_id = ?, salesman_id = ?, cp_id = ?, transaction_description = ?, marge_total = ?, marge_percent = ?
          , order_probability = ?, expected_billing_date = ?
        WHERE id = ?|;
@@ -768,7 +828,7 @@ SQL
              $form->{delivered} ? "t" : "f", $form->{proforma} ? 't' : 'f',
              $quotation, conv_i($form->{department_id}),
              conv_i($form->{language_id}), conv_i($form->{taxzone_id}),
-             conv_i($form->{shipto_id}), conv_i($form->{payment_id}),
+             conv_i($form->{shipto_id}), conv_i($form->{billing_address_id}), conv_i($form->{payment_id}),
              conv_i($form->{delivery_vendor_id}),
              conv_i($form->{delivery_customer_id}),
              conv_i($form->{delivery_term_id}),
@@ -832,11 +892,77 @@ SQL
                                        config_yaml => $form->{periodic_invoices_config})
     if ($form->{type} eq 'sales_order');
 
+  $self->_link_created_sales_order_to_requirement_specs_for_sales_quotations(
+    type               => $form->{type},
+    converted_from_ids => \@convert_from_oe_ids,
+    sales_order_id     => $form->{id},
+    is_new             => $is_new,
+  );
+
+  $self->_set_project_in_linked_requirement_spec(
+    type           => $form->{type},
+    project_id     => $form->{globalproject_id},
+    sales_order_id => $form->{id},
+  );
+
   $main::lxdebug->leave_sub();
 
   return 1;
 }
 
+sub _link_created_sales_order_to_requirement_specs_for_sales_quotations {
+  my ($self, %params) = @_;
+
+  # If this is a sales order created from a sales quotation and if
+  # that sales quotation was created from a requirement spec document
+  # then link the newly created sales order to the requirement spec
+  # document, too.
+
+  return if !$params{is_new};
+  return if  $params{type} ne 'sales_order';
+  return if !@{ $params{converted_from_ids} };
+
+  my $oe_objects       = SL::DB::Manager::Order->get_all(where => [ id => $params{converted_from_ids} ]);
+  my @sales_quotations = grep { $_->is_type('sales_quotation') } @{ $oe_objects };
+
+  return if !@sales_quotations;
+
+  my $rs_orders = SL::DB::Manager::RequirementSpecOrder->get_all(where => [ order_id => [ map { $_->id } @sales_quotations ] ]);
+
+  return if !@{ $rs_orders };
+
+  $rs_orders->[0]->db->with_transaction(sub {
+    foreach my $rs_order (@{ $rs_orders }) {
+      SL::DB::RequirementSpecOrder->new(
+        order_id            => $params{sales_order_id},
+        requirement_spec_id => $rs_order->requirement_spec_id,
+        version_id          => $rs_order->version_id,
+      )->save;
+    }
+
+    1;
+  });
+}
+
+sub _set_project_in_linked_requirement_spec {
+  my ($self, %params) = @_;
+
+  return if  $params{type} ne 'sales_order';
+  return if !$params{project_id} || !$params{sales_order_id};
+
+  my $query = <<SQL;
+    UPDATE requirement_specs
+    SET project_id = ?
+    WHERE id IN (
+      SELECT so.requirement_spec_id
+      FROM requirement_spec_orders so
+      WHERE so.order_id = ?
+    )
+SQL
+
+  do_query($::form, $::form->get_standard_dbh, $query, $params{project_id}, $params{sales_order_id});
+}
+
 sub save_periodic_invoices_config {
   my ($self, %params) = @_;
 
@@ -1032,7 +1158,7 @@ sub _retrieve {
            o.closed, o.reqdate, o.tax_point, o.quonumber, o.department_id, o.cusordnumber,
            o.mtime, o.itime,
            d.description AS department, o.payment_id, o.language_id, o.taxzone_id,
-           o.delivery_customer_id, o.delivery_vendor_id, o.proforma, o.shipto_id,
+           o.delivery_customer_id, o.delivery_vendor_id, o.proforma, o.shipto_id, o.billing_address_id,
            o.globalproject_id, o.delivered, o.transaction_description, o.delivery_term_id,
            o.itime::DATE AS insertdate, o.order_probability, o.expected_billing_date
          FROM oe o
index 79123b1..9f525b3 100644 (file)
@@ -2,10 +2,12 @@ package SL::Presenter::DeliveryOrder;
 
 use strict;
 
+use SL::DB::DeliveryOrder::TypeData ();
+use SL::Locale::String qw(t8);
 use SL::Presenter::EscapedText qw(escape is_escaped);
 
 use Exporter qw(import);
-our @EXPORT_OK = qw(sales_delivery_order purchase_delivery_order);
+our @EXPORT_OK = qw(sales_delivery_order purchase_delivery_order delivery_order_status_line);
 
 use Carp;
 
@@ -15,12 +17,39 @@ sub sales_delivery_order {
   return _do_record($delivery_order, 'sales_delivery_order', %params);
 }
 
+sub rma_delivery_order {
+  my ($delivery_order, %params) = @_;
+
+  return _do_new_record($delivery_order, 'rma_delivery_order', %params);
+}
+
 sub purchase_delivery_order {
   my ($delivery_order, %params) = @_;
 
   return _do_record($delivery_order, 'purchase_delivery_order', %params);
 }
 
+sub supplier_delivery_order {
+  my ($delivery_order, %params) = @_;
+
+  return _do_new_record($delivery_order, 'supplier_delivery_order', %params);
+}
+
+sub _do_new_record {
+  my ($delivery_order, $type, %params) = @_;
+
+  $params{display} ||= 'inline';
+
+  croak "Unknown display type '$params{display}'" unless $params{display} =~ m/^(?:inline|table-cell)$/;
+
+  my $text = join '', (
+    $params{no_link} ? '' : '<a href="contoller.pl?action=DeliveryOrder/edit&amp;type=' . $type . '&amp;id=' . escape($delivery_order->id) . '">',
+    escape($delivery_order->donumber),
+    $params{no_link} ? '' : '</a>',
+  );
+  is_escaped($text);
+}
+
 sub _do_record {
   my ($delivery_order, $type, %params) = @_;
 
@@ -36,6 +65,36 @@ sub _do_record {
   is_escaped($text);
 }
 
+sub stock_status {
+  my ($delivery_order) = @_;
+
+  my $in_out = SL::DB::DeliveryOrder::TypeData::get3($delivery_order->type, "properties", "transfer");
+
+  if ($in_out eq 'in') {
+    return escape($delivery_order->delivered ? t8('transferred in') : t8('not transferred in yet'));
+  }
+
+  if ($in_out eq 'out') {
+    return escape($delivery_order->delivered ? t8('transferred out') : t8('not transferred out yet'));
+  }
+}
+
+sub closed_status {
+  my ($delivery_order) = @_;
+
+  return escape($delivery_order->closed ? t8('Closed') : t8('Open'))
+}
+
+sub status_line {
+  my ($delivery_order) = @_;
+
+  return "" unless $delivery_order->id;
+
+  stock_status($delivery_order) . " ; " . closed_status($delivery_order)
+}
+
+sub delivery_order_status_line { goto &status_line };
+
 1;
 
 __END__
index db68fa6..592af55 100644 (file)
@@ -48,12 +48,14 @@ sub grouped_record_list {
   $output .= _sales_quotation_list(        $groups{sales_quotations},         %params) if $groups{sales_quotations};
   $output .= _sales_order_list(            $groups{sales_orders},             %params) if $groups{sales_orders};
   $output .= _sales_delivery_order_list(   $groups{sales_delivery_orders},    %params) if $groups{sales_delivery_orders};
+  $output .= _rma_delivery_order_list(     $groups{rma_delivery_orders},      %params) if $groups{rma_delivery_orders};
   $output .= _sales_invoice_list(          $groups{sales_invoices},           %params) if $groups{sales_invoices};
   $output .= _ar_transaction_list(         $groups{ar_transactions},          %params) if $groups{ar_transactions};
 
   $output .= _request_quotation_list(      $groups{purchase_quotations},      %params) if $groups{purchase_quotations};
   $output .= _purchase_order_list(         $groups{purchase_orders},          %params) if $groups{purchase_orders};
   $output .= _purchase_delivery_order_list($groups{purchase_delivery_orders}, %params) if $groups{purchase_delivery_orders};
+  $output .= _supplier_delivery_order_list($groups{supplier_delivery_orders}, %params) if $groups{supplier_delivery_orders};
   $output .= _purchase_invoice_list(       $groups{purchase_invoices},        %params) if $groups{purchase_invoices};
   $output .= _ap_transaction_list(         $groups{ap_transactions},          %params) if $groups{ap_transactions};
 
@@ -183,12 +185,14 @@ sub _group_records {
     shop_orders              => sub { (ref($_[0]) eq 'SL::DB::ShopOrder')       &&  $_[0]->id                           },
     sales_quotations         => sub { (ref($_[0]) eq 'SL::DB::Order')           &&  $_[0]->is_type('sales_quotation')   },
     sales_orders             => sub { (ref($_[0]) eq 'SL::DB::Order')           &&  $_[0]->is_type('sales_order')       },
-    sales_delivery_orders    => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   &&  $_[0]->is_sales                     },
+    sales_delivery_orders    => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   &&  $_[0]->is_type('sales_delivery_order') },
+    rma_delivery_orders      => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   &&  $_[0]->is_type('rma_delivery_order')   },
     sales_invoices           => sub { (ref($_[0]) eq 'SL::DB::Invoice')         &&  $_[0]->invoice                      },
     ar_transactions          => sub { (ref($_[0]) eq 'SL::DB::Invoice')         && !$_[0]->invoice                      },
     purchase_quotations      => sub { (ref($_[0]) eq 'SL::DB::Order')           &&  $_[0]->is_type('request_quotation') },
     purchase_orders          => sub { (ref($_[0]) eq 'SL::DB::Order')           &&  $_[0]->is_type('purchase_order')    },
-    purchase_delivery_orders => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   && !$_[0]->is_sales                     },
+    purchase_delivery_orders => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   &&  $_[0]->is_type('purchase_delivery_order') },
+    supplier_delivery_orders => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   &&  $_[0]->is_type('supplier_delivery_order') },
     purchase_invoices        => sub { (ref($_[0]) eq 'SL::DB::PurchaseInvoice') &&  $_[0]->invoice                      },
     ap_transactions          => sub { (ref($_[0]) eq 'SL::DB::PurchaseInvoice') && !$_[0]->invoice                      },
     sepa_collections         => sub { (ref($_[0]) eq 'SL::DB::SepaExportItem')  &&  $_[0]->ar_id                        },
@@ -364,6 +368,27 @@ sub _sales_delivery_order_list {
   );
 }
 
+sub _rma_delivery_order_list {
+  my ($list, %params) = @_;
+
+  return record_list(
+    $list,
+    title   => $::locale->text('RMA Delivery Orders'),
+    type    => 'rma_delivery_order',
+    columns => [
+      [ $::locale->text('Delivery Order Date'),     'transdate'                                                                ],
+      [ $::locale->text('Delivery Order Number'),   sub { $_[0]->presenter->rma_delivery_order(display => 'table-cell') }    ],
+      [ $::locale->text('Order Number'),            'ordnumber' ],
+      [ $::locale->text('Customer'),                'customer'                                                                 ],
+      [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
+      [ $::locale->text('Project'),                 'globalproject', ],
+      [ $::locale->text('Delivered'),               'delivered'                                                                ],
+      [ $::locale->text('Closed'),                  'closed'                                                                   ],
+    ],
+    %params,
+  );
+}
+
 sub _purchase_delivery_order_list {
   my ($list, %params) = @_;
 
@@ -385,6 +410,27 @@ sub _purchase_delivery_order_list {
   );
 }
 
+sub _supplier_delivery_order_list {
+  my ($list, %params) = @_;
+
+  return record_list(
+    $list,
+    title   => $::locale->text('Supplier Delivery Orders'),
+    type    => 'supplier_delivery_order',
+    columns => [
+      [ $::locale->text('Delivery Order Date'),     'transdate'                                                                ],
+      [ $::locale->text('Delivery Order Number'),   sub { $_[0]->presenter->supplier_delivery_order(display => 'table-cell') } ],
+      [ $::locale->text('Order Number'),            'ordnumber' ],
+      [ $::locale->text('Vendor'),                  'vendor'                                                                 ],
+      [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
+      [ $::locale->text('Project'),                 'globalproject', ],
+      [ $::locale->text('Delivered'),               'delivered'                                                                ],
+      [ $::locale->text('Closed'),                  'closed'                                                                   ],
+    ],
+    %params,
+  );
+}
+
 sub _sales_invoice_list {
   my ($list, %params) = @_;
 
@@ -662,6 +708,8 @@ The order in which the records are grouped is:
 
 =item * sales delivery orders
 
+=item * rma delivery orders
+
 =item * sales invoices
 
 =item * AR transactions
@@ -672,6 +720,8 @@ The order in which the records are grouped is:
 
 =item * purchase delivery orders
 
+=item * supplier delivery orders
+
 =item * purchase invoices
 
 =item * AP transactions
index 032b179..a140fe4 100644 (file)
@@ -10,7 +10,7 @@ use Exporter qw(import);
 our @EXPORT_OK = qw(
   html_tag input_tag hidden_tag javascript man_days_tag name_to_id select_tag
   checkbox_tag button_tag submit_tag ajax_submit_tag input_number_tag
-  stringify_attributes restricted_html textarea_tag link_tag date_tag
+  stringify_attributes textarea_tag link_tag date_tag
   div_tag radio_button_tag img_tag);
 our %EXPORT_TAGS = (ALL => \@EXPORT_OK);
 
@@ -247,6 +247,9 @@ sub select_tag {
 sub checkbox_tag {
   my ($name, %attributes) = @_;
 
+  my %label_attributes = map { (substr($_, 6) => $attributes{$_}) } grep { m{^label_} } keys %attributes;
+  delete @attributes{grep { m{^label_} } keys %attributes};
+
   _set_id_attribute(\%attributes, $name);
 
   $attributes{value}   = 1 unless defined $attributes{value};
@@ -263,7 +266,7 @@ sub checkbox_tag {
   my $code  = '';
   $code    .= hidden_tag($name, 0, %attributes, id => $attributes{id} . '_hidden') if $for_submit;
   $code    .= html_tag('input', undef,  %attributes, name => $name, type => 'checkbox');
-  $code    .= html_tag('label', $label, for => $attributes{id}) if $label;
+  $code    .= html_tag('label', $label, for => $attributes{id}, %label_attributes) if $label;
   $code    .= javascript(qq|\$('#$attributes{id}').checkall('$checkall');|) if $checkall;
 
   return $code;
@@ -272,6 +275,9 @@ sub checkbox_tag {
 sub radio_button_tag {
   my ($name, %attributes) = @_;
 
+  my %label_attributes = map { (substr($_, 6) => $attributes{$_}) } grep { m{^label_} } keys %attributes;
+  delete @attributes{grep { m{^label_} } keys %attributes};
+
   $attributes{value}   = 1 unless exists $attributes{value};
 
   _set_id_attribute(\%attributes, $name, 1);
@@ -286,7 +292,7 @@ sub radio_button_tag {
   }
 
   my $code  = html_tag('input', undef,  %attributes, name => $name, type => 'radio');
-  $code    .= html_tag('label', $label, for => $attributes{id}) if $label;
+  $code    .= html_tag('label', $label, for => $attributes{id}, %label_attributes) if $label;
 
   return $code;
 }
@@ -363,13 +369,6 @@ sub _set_id_attribute {
 
 my $html_restricter;
 
-sub restricted_html {
-  my ($value) = @_;
-
-  $html_restricter ||= SL::HTML::Restrict->create;
-  return $html_restricter->process($value);
-}
-
 sub textarea_tag {
   my ($name, $content, %attributes) = @_;
 
@@ -494,10 +493,6 @@ Creates a string from all elements in C<%items> suitable for usage as
 HTML tag attributes. Keys and values are HTML escaped even though keys
 must not contain non-ASCII characters for browsers to accept them.
 
-=item C<restricted_html $html>
-
-Returns HTML stripped of unknown tags. See L<SL::HTML::Restrict>.
-
 =back
 
 =head2 HIGH-LEVEL FUNCTIONS
@@ -574,7 +569,10 @@ C<name_to_id($name)>. The tag's C<value> defaults to C<1>.
 
 If C<%attributes> contains a key C<label> then a HTML 'label' tag is
 created with said C<label>. No attribute named C<label> is created in
-that case.
+that case. Furthermore, all attributes whose names start with
+C<label_> become attributes on the label tag without the C<label_>
+prefix. For example, C<label_style='#ff0000'> will be turned into
+C<style='#ff0000'> on the label tag, causing the text to become red.
 
 If C<%attributes> contains a key C<checkall> then the value is taken as a
 JQuery selector and clicking this checkbox will also toggle all checkboxes
@@ -588,7 +586,10 @@ C<1>. The tag's C<id> defaults to C<name_to_id($name . "_" . $value)>.
 
 If C<%attributes> contains a key C<label> then a HTML 'label' tag is
 created with said C<label>. No attribute named C<label> is created in
-that case.
+that case. Furthermore, all attributes whose names start with
+C<label_> become attributes on the label tag without the C<label_>
+prefix. For example, C<label_style='#ff0000'> will be turned into
+C<style='#ff0000'> on the label tag, causing the text to become red.
 
 =item C<select_tag $name, \@collection, %attributes>
 
index dd855fc..7d56d94 100644 (file)
@@ -3,13 +3,17 @@ package SL::Presenter::Text;
 use strict;
 
 use SL::Presenter::EscapedText qw(escape);
+use SL::HTML::Restrict;
+use SL::HTML::Util;
 
 use Exporter qw(import);
-our @EXPORT_OK = qw(format_man_days simple_format truncate);
+our @EXPORT_OK = qw(format_man_days simple_format truncate restricted_html);
 our %EXPORT_TAGS = (ALL => \@EXPORT_OK);
 
 use Carp;
 
+my $html_cleaner;
+
 sub truncate {
   my ($text, %params) = @_;
 
@@ -43,6 +47,17 @@ sub format_man_days {
   escape($output);
 }
 
+sub restricted_html {
+  my ($value) = @_;
+  $html_cleaner //= SL::HTML::Restrict->create;
+  return $html_cleaner->process($value);
+}
+
+sub stripped_html {
+  my ($value) = @_;
+  return SL::HTML::Util::strip($value);
+}
+
 1;
 __END__
 
@@ -89,6 +104,16 @@ paragraph change: they close the current paragraph tag and start a new
 one. Single newlines are converted to line breaks. Carriage returns
 are removed.
 
+=item C<restricted_html $unsafe_html>
+
+Returns HTML code stripped from unwanted/unsupported content. This is
+done via the module L<SL::HTML::Restrict>.
+
+=item C<stripped_html $html>
+
+Returns the raw text with all HTML tags and comments stripped. This is
+done via L<SL::HTML::Util/strip>.
+
 =back
 
 =head1 BUGS
index ef93e73..28d01af 100644 (file)
--- a/SL/RP.pm
+++ b/SL/RP.pm
@@ -1296,9 +1296,9 @@ sub aging {
     SELECT ${ct}.id AS ctid, ${ct}.name,
       street, zipcode, city, country, contact, email,
       phone as customerphone, fax as customerfax, ${ct}number,
-      "invnumber", "transdate",
+      "invnumber", "transdate", "type",
       (amount - COALESCE((SELECT sum(amount)*$ml FROM acc_trans WHERE chart_link ilike '%paid%' AND acc_trans.trans_id=${arap}.id AND acc_trans.transdate <= (date $todate)),0)) as "open", "amount",
-      "duedate", invoice, ${arap}.id, date_part('days', now() - duedate) as overduedays,
+      "duedate", invoice, ${arap}.id, date_part('days', now() - duedate) as overduedays, datepaid, (amount - paid) as current_open,
       (SELECT $buysell
        FROM exchangerate
        WHERE (${arap}.currency_id = exchangerate.currency_id)
index 18940c3..da5d54a 100644 (file)
@@ -203,7 +203,7 @@ sub delete {
     do_query($form, $dbh, $query, @where_values);
 
     1;
-  }) or die { SL::DD->client->error };
+  }) or die { SL::DB->client->error };
 
   $main::lxdebug->leave_sub();
 }
index e4bf360..a4cf5f5 100644 (file)
@@ -143,7 +143,7 @@ sub to_xml {
   my $is_coll   = $self->{collection};
   my $cd_src    = $is_coll ? 'Cdtr'              : 'Dbtr';
   my $cd_dst    = $is_coll ? 'Dbtr'              : 'Cdtr';
-  my $pain_id   = $is_coll ? 'pain.008.002.02'   : 'pain.001.002.03';
+  my $pain_id   = $is_coll ? 'pain.008.001.02'   : 'pain.001.001.03';
   my $pain_elmt = $is_coll ? 'CstmrDrctDbtInitn' : 'CstmrCdtTrfInitn';
   my @pii_base  = (strftime('PII%Y%m%d%H%M%S', @now), rand(1000000000));
 
index 3f29c99..1b1b0c8 100644 (file)
@@ -3,26 +3,25 @@ package SL::ShopConnector::ALL;
 use strict;
 
 use SL::ShopConnector::Shopware;
+use SL::ShopConnector::Shopware6;
 use SL::ShopConnector::WooCommerce;
 
 my %shop_connector_by_name = (
   shopware    => 'SL::ShopConnector::Shopware',
-  woocommerce    => 'SL::ShopConnector::WooCommerce',
-);
-
-my %shop_connector_by_connector = (
-  shopware   => 'SL::ShopConnector::Shopware',
+  shopware6   => 'SL::ShopConnector::Shopware6',
   woocommerce => 'SL::ShopConnector::WooCommerce',
 );
 
 my @shop_connector_order = qw(
   woocommerce
   shopware
+  shopware6
 );
 
 my @shop_connectors = (
-  { id => "shopware",   description => "Shopware" },
-  { id => "woocommerce",   description => "WooCommerce" },
+  { id => "shopware",    description => "Shopware" },
+  { id => "shopware6",   description => "Shopware6" },
+  { id => "woocommerce", description => "WooCommerce" },
 );
 
 
@@ -34,10 +33,6 @@ sub shop_connector_class_by_name {
   $shop_connector_by_name{$_[1]};
 }
 
-sub shop_connector_class_by_connector {
-  $shop_connector_by_connector{$_[1]};
-}
-
 sub connectors {
   \@shop_connectors;
 }
index 56127e4..1dc4a2e 100644 (file)
@@ -7,17 +7,63 @@ use Rose::Object::MakeMethods::Generic (
   scalar => [ qw(config) ],
 );
 
-sub get_one_order  { die 'get_one_order needs to be implemented' }
+sub get_one_order  {
+  die 'get_one_order needs to be implemented';
+
+  my ($self, $ordnumber) = @_;
+  my %fetched_order;
+
+  # 1. fetch the order and import it as a kivi order
+  # 2. update the order state for report
+  # 3. return a hash with either success or error state
+  my $one_order; # REST call
+
+  my $error = $self->import_data_to_shop_order($one_order);
+
+  $self->set_orderstatus($one_order->{id}, "fetched") unless $error;
+
+  return \(
+      shop_id          => $self->config->id,
+      shop_description => $self->config->description,
+      number_of_orders => $error ? 0 : 1,
+      message          => $error ? "Error: $error->{msg}"  : '',
+      error            => $error ? 1 : 0,
+    );
+}
+
 
 sub get_new_orders { die 'get_order needs to be implemented' }
 
-sub update_part    { die 'update_part needs to be implemented' }
+sub update_part    {
+  die 'update_part needs to be implemented';
+
+  my ($self, $shop_part, $todo) = @_;
+  #shop_part is passed as a param
+  die "Need a valid Shop Part for updating Part" unless ref($shop_part) eq 'SL::DB::ShopPart';
+  die "Invalid todo for updating Part"           unless $todo =~ m/(price|stock|price_stock|active|all)/;
+
+  my $part = SL::DB::Part->new(id => $shop_part->part_id)->load;
+  die "Shop Part but no kivi Part?" unless ref $part eq 'SL::DB::Part';
+
+  my $success;
+
+  return $success ? 1 : 0;
+}
 
 sub get_article    { die 'get_article needs to be implemented' }
 
 sub get_categories { die 'get_categories needs to be implemented' }
 
-sub get_version    { die 'get_version needs to be implemented' }
+sub get_version    {
+
+  die 'get_version needs to be implemented';
+  # has to return a hashref with this structure:
+  # version has to return the connection error message
+  my $connect = {};
+  $connect->{success}         = 0 || 1;
+  $connect->{data}->{version} = '1234';
+  return $connect;
+}
 
 sub set_orderstatus { die 'set_orderstatus needs to be implemented' }
 
@@ -40,11 +86,37 @@ __END__
 
 =over 4
 
-=item C<get_one_order>
+=item C<get_one_order $ordnumber>
+
+Needs a order number and fetch (one or more) orders
+which are returned by the Shop system. The function
+has to take care of getting the order including customer
+and item information to kivi.
+It has to return a hash with either the number of succesful
+imported order or within the same hash structure a error message.
+
+
 
 =item C<get_new_orders>
 
-=item C<update_part>
+=item C<update_part $shop_part $todo>
+
+Updates one Part including all metadata and Images in a Shop.
+Needs a valid 'SL::DB::ShopPart' as first parameter and a requested action
+as second parameter. Valid values for the second parameter are
+"price, stock, price_stock, active, all".
+The method updates either all metadata or a subset.
+Name and action for the subsets:
+
+ price       => updates only the price
+ stock       => updates only the available stock (qty)
+ price_stock => combines both predecessors
+ active      => updates only the state of the shop part
+
+Images should always be updated, regardless of the requested action.
+Returns 1 if all updates were executed successful.
+
+
 
 =item C<get_article>
 
@@ -52,8 +124,23 @@ __END__
 
 =item C<get_version>
 
+IMPORTANT: This call is used to test the connection and if succesful
+it returns the version number of the shop. If not succesful the
+returning function has to make sure a error string is returned in
+the same data structure. Details of the returning hashref:
+
+ my $connect = {};
+ $connect->{success}         = 0 || 1;
+ $connect->{data}->{version} = '1234';
+ return $connect;
+
 =item C<set_orderstatus>
 
+Sets the state of the order in the Shop.
+Valid values depend on the Shop API, common states
+are delivered, fetched, paid, in progress ...
+
+
 =back
 
 =head1 SEE ALSO
index a777ddf..65c42fd 100644 (file)
@@ -468,7 +468,7 @@ __END__
 
 =head1 NAME
 
-SL::Shopconnecter::Shopware - connector for shopware 5
+SL::Shopconnector::Shopware - connector for shopware 5
 
 =head1 SYNOPSIS
 
diff --git a/SL/ShopConnector/Shopware6.pm b/SL/ShopConnector/Shopware6.pm
new file mode 100644 (file)
index 0000000..6d04a1b
--- /dev/null
@@ -0,0 +1,1095 @@
+package SL::ShopConnector::Shopware6;
+
+use strict;
+
+use parent qw(SL::ShopConnector::Base);
+
+use Carp;
+use Encode qw(encode);
+use List::Util qw(first);
+use REST::Client;
+use Try::Tiny;
+
+use SL::JSON;
+use SL::Helper::Flash;
+use SL::Locale::String qw(t8);
+
+use Rose::Object::MakeMethods::Generic (
+  'scalar --get_set_init' => [ qw(connector) ],
+);
+
+sub all_open_orders {
+  my ($self) = @_;
+
+  my $assoc = {
+              'associations' => {
+                'deliveries'   => {
+                  'associations' => {
+                    'shippingMethod' => [],
+                      'shippingOrderAddress' => {
+                        'associations' => {
+                                            'salutation'   => [],
+                                            'country'      => [],
+                                            'countryState' => []
+                                          }
+                                                }
+                                     }
+                                   }, # end deliveries
+                'language' => [],
+                'orderCustomer' => [],
+                'addresses' => {
+                  'associations' => {
+                                      'salutation'   => [],
+                                      'countryState' => [],
+                                      'country'      => []
+                                    }
+                                },
+                'tags' => [],
+                'lineItems' => {
+                  'associations' => {
+                    'product' => {
+                      'associations' => {
+                                          'tax' => []
+                                        }
+                                 }
+                                    }
+                                }, # end line items
+                'salesChannel' => [],
+                  'documents' => {          # currently not used
+                    'associations' => {
+                      'documentType' => []
+                                      }
+                                 },
+                'transactions' => {
+                  'associations' => {
+                    'paymentMethod' => []
+                                    }
+                                  },
+                'currency' => []
+            }, # end associations
+         'limit' => $self->config->orders_to_fetch ? $self->config->orders_to_fetch : undef,
+        # 'page' => 1,
+     'aggregations' => [
+                            {
+                              'field'      => 'billingAddressId',
+                              'definition' => 'order_address',
+                              'name'       => 'BillingAddress',
+                              'type'       => 'entity'
+                            }
+                          ],
+        'filter' => [
+                     {
+                        'value' => 'open', # open or completed (mind the past)
+                        'type' => 'equals',
+                        'field' => 'order.stateMachineState.technicalName'
+                      }
+                    ],
+        'total-count-mode' => 0
+      };
+  return $assoc;
+}
+
+# used for get_new_orders and get_one_order
+sub get_fetched_order_structure {
+  my ($self) = @_;
+  # set known params for the return structure
+  my %fetched_order  = (
+      shop_id          => $self->config->id,
+      shop_description => $self->config->description,
+      message          => '',
+      error            => '',
+      number_of_orders => 0,
+    );
+  return %fetched_order;
+}
+
+sub update_part {
+  my ($self, $shop_part, $todo) = @_;
+
+  #shop_part is passed as a param
+  croak t8("Need a valid Shop Part for updating Part") unless ref($shop_part) eq 'SL::DB::ShopPart';
+  croak t8("Invalid todo for updating Part")           unless $todo =~ m/(price|stock|price_stock|active|all)/;
+
+  my $part = SL::DB::Part->new(id => $shop_part->part_id)->load;
+  die "Shop Part but no kivi Part?" unless ref $part eq 'SL::DB::Part';
+
+  my $tax_n_price = $shop_part->get_tax_and_price;
+  my $price       = $tax_n_price->{price};
+  my $taxrate     = $tax_n_price->{tax};
+
+  # simple calc for both cases, always give sw6 the calculated gross price
+  my ($net, $gross);
+  if ($self->config->pricetype eq 'brutto') {
+    $gross = $price;
+    $net   = $price / (1 + $taxrate/100);
+  } elsif ($self->config->pricetype eq 'netto') {
+    $net   = $price;
+    $gross = $price * (1 + $taxrate/100);
+  } else { die "Invalid state for price type"; }
+
+  my $update_p;
+  $update_p->{productNumber} = $part->partnumber;
+  $update_p->{name}          = _u8($part->description);
+  $update_p->{description}   =   $shop_part->shop->use_part_longdescription
+                               ? _u8($part->notes)
+                               : _u8($shop_part->shop_description);
+
+  # locales simple check for english
+  my $english = SL::DB::Manager::Language->get_first(query => [ description   => { ilike => 'Englisch' },
+                                                        or => [ template_code => { ilike => 'en' } ],
+                                                    ]);
+  if (ref $english eq 'SL::DB::Language') {
+    # add english translation for product
+    # TODO (or not): No Translations for shop_part->shop_description available
+    my $translation = first { $english->id == $_->language_id } @{ $part->translations };
+    $update_p->{translations}->{'en-GB'}->{name}        = _u8($translation->{translation});
+    $update_p->{translations}->{'en-GB'}->{description} = _u8($translation->{longdescription});
+  }
+
+  $update_p->{stock}  = $::form->round_amount($part->onhand, 0) if ($todo =~ m/(stock|all)/);
+  # JSON::true JSON::false
+  # These special values become JSON true and JSON false values, respectively.
+  # You can also use \1 and \0 directly if you want
+  $update_p->{active} = (!$part->obsolete && $part->shop) ? \1 : \0 if ($todo =~ m/(active|all)/);
+
+  # 1. check if there is already a product
+  my $product_filter = {
+          'filter' => [
+                        {
+                          'value' => $part->partnumber,
+                          'type'  => 'equals',
+                          'field' => 'productNumber'
+                        }
+                      ]
+    };
+  my $ret = $self->connector->POST('api/search/product', to_json($product_filter));
+  my $response_code = $ret->responseCode();
+  die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 200;
+
+  my $one_d; # maybe empty
+  try {
+    $one_d = from_json($ret->responseContent())->{data}->[0];
+  } catch { die "Malformed JSON Data: $_ " . $ret->responseContent();  };
+  # edit or create if not found
+  if ($one_d->{id}) {
+    #update
+    # we need price object structure and taxId
+    $update_p->{$_} = $one_d->{$_} foreach qw(taxId price);
+    if ($todo =~ m/(price|all)/) {
+      $update_p->{price}->[0]->{gross} = $gross;
+    }
+    undef $update_p->{partNumber}; # we dont need this one
+    $ret = $self->connector->PATCH('api/product/' . $one_d->{id}, to_json($update_p));
+    unless (204 == $ret->responseCode()) {
+      die t8('Part Description is too long for this Shopware version. It should have lower than 255 characters.')
+         if $ret->responseContent() =~ m/Diese Zeichenkette ist zu lang. Sie sollte.*255 Zeichen/;
+      die "Updating part with " .  $part->partnumber . " failed: " . $ret->responseContent() unless (204 == $ret->responseCode());
+    }
+  } else {
+    # create part
+    # 1. get the correct tax for this product
+    my $tax_filter = {
+          'filter' => [
+                        {
+                          'value' => $taxrate,
+                          'type' => 'equals',
+                          'field' => 'taxRate'
+                        }
+                      ]
+        };
+    $ret = $self->connector->POST('api/search/tax', to_json($tax_filter));
+    die "Search for Tax with rate: " .  $part->partnumber . " failed: " . $ret->responseContent() unless (200 == $ret->responseCode());
+    try {
+      $update_p->{taxId} = from_json($ret->responseContent())->{data}->[0]->{id};
+    } catch { die "Malformed JSON Data or Taxkey entry missing: $_ " . $ret->responseContent();  };
+
+    # 2. get the correct currency for this product
+    my $currency_filter = {
+        'filter' => [
+                      {
+                        'value' => SL::DB::Default->get_default_currency,
+                        'type' => 'equals',
+                        'field' => 'isoCode'
+                      }
+                    ]
+      };
+    $ret = $self->connector->POST('api/search/currency', to_json($currency_filter));
+    die "Search for Currency with ISO Code: " . SL::DB::Default->get_default_currency . " failed: "
+      . $ret->responseContent() unless (200 == $ret->responseCode());
+
+    try {
+      $update_p->{price}->[0]->{currencyId} = from_json($ret->responseContent())->{data}->[0]->{id};
+    } catch { die "Malformed JSON Data or Currency ID entry missing: $_ " . $ret->responseContent();  };
+
+    # 3. add net and gross price and allow variants
+    $update_p->{price}->[0]->{gross}  = $gross;
+    $update_p->{price}->[0]->{net}    = $net;
+    $update_p->{price}->[0]->{linked} = \1; # link product variants
+
+    $ret = $self->connector->POST('api/product', to_json($update_p));
+    die "Create for Product " .  $part->partnumber . " failed: " . $ret->responseContent() unless (204 == $ret->responseCode());
+  }
+
+  # if there are images try to sync this with the shop_part
+  try {
+    $self->sync_all_images(shop_part => $shop_part, set_cover => 1, delete_orphaned => 1);
+  } catch { die "Could not sync images for Part " . $part->partnumber . " Reason: $_" };
+
+  # if there are categories try to sync this with the shop_part
+  try {
+    $self->sync_all_categories(shop_part => $shop_part);
+  } catch { die "Could not sync Categories for Part " . $part->partnumber . " Reason: $_" };
+
+  return 1; # no invalid response code -> success
+}
+sub sync_all_categories {
+  my ($self, %params) = @_;
+
+  my $shop_part = delete $params{shop_part};
+  croak "Need a valid Shop Part for updating Images" unless ref($shop_part) eq 'SL::DB::ShopPart';
+
+  my $partnumber = $shop_part->part->partnumber;
+  die "Shop Part but no kivi Partnumber" unless $partnumber;
+
+  my ($ret, $response_code);
+  # 1 get  uuid for product
+  my $product_filter = {
+          'filter' => [
+                        {
+                          'value' => $partnumber,
+                          'type'  => 'equals',
+                          'field' => 'productNumber'
+                        }
+                      ]
+    };
+
+  $ret = $self->connector->POST('api/search/product', to_json($product_filter));
+  $response_code = $ret->responseCode();
+  die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 200;
+  my ($product_id, $category_tree);
+  try {
+    $product_id    = from_json($ret->responseContent())->{data}->[0]->{id};
+    $category_tree = from_json($ret->responseContent())->{data}->[0]->{categoryIds};
+  } catch { die "Malformed JSON Data: $_ " . $ret->responseContent();  };
+  my $cat;
+  # if the part is connected to a category at all
+  if ($shop_part->shop_category) {
+    foreach my $row_cat (@{ $shop_part->shop_category }) {
+      $cat->{@{ $row_cat }[0]} = @{ $row_cat }[1];
+    }
+  }
+  # delete
+  foreach my $shopware_cat (@{ $category_tree }) {
+    if ($cat->{$shopware_cat}) {
+      # cat exists and no delete
+      delete $cat->{$shopware_cat};
+      next;
+    }
+    # cat exists and delete
+    $ret = $self->connector->DELETE("api/product/$product_id/categories/$shopware_cat");
+    $response_code = $ret->responseCode();
+    die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 204;
+  }
+  # now add only new categories
+  my $p;
+  $p->{id}  = $product_id;
+  $p->{categories} = ();
+  foreach my $new_cat (keys %{ $cat }) {
+    push @{ $p->{categories} }, {id => $new_cat};
+  }
+    $ret = $self->connector->PATCH("api/product/$product_id", to_json($p));
+    $response_code = $ret->responseCode();
+    die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 204;
+}
+
+sub sync_all_images {
+  my ($self, %params) = @_;
+
+  $params{set_cover}       //= 1;
+  $params{delete_orphaned} //= 0;
+
+  my $shop_part = delete $params{shop_part};
+  croak "Need a valid Shop Part for updating Images" unless ref($shop_part) eq 'SL::DB::ShopPart';
+
+  my $partnumber = $shop_part->part->partnumber;
+  die "Shop Part but no kivi Partnumber" unless $partnumber;
+
+  my @upload_img  = $shop_part->get_images(want_binary => 1);
+
+  return unless (@upload_img); # there are no images, but delete wont work TODO extract to method
+
+  my ($ret, $response_code);
+  # 1. get part uuid and get media associations
+  # 2. create or update the media entry for the filename
+  # 2.1 if no media entry exists create one
+  # 2.2 update file
+  # 2.2 create or update media_product and set position
+  # 3. optional set cover image
+  # 4. optional delete images in shopware which are not in kivi
+
+  # 1 get mediaid uuid for prodcut
+  my $product_filter = {
+              'associations' => {
+                'media'   => []
+              },
+          'filter' => [
+                        {
+                          'value' => $partnumber,
+                          'type'  => 'equals',
+                          'field' => 'productNumber'
+                        }
+                      ]
+    };
+
+  $ret = $self->connector->POST('api/search/product', to_json($product_filter));
+  $response_code = $ret->responseCode();
+  die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 200;
+  my ($product_id, $media_data);
+  try {
+    $product_id = from_json($ret->responseContent())->{data}->[0]->{id};
+    # $media_data = from_json($ret->responseContent())->{data}->[0]->{media};
+  } catch { die "Malformed JSON Data: $_ " . $ret->responseContent();  };
+
+  # 2 iterate all kivi images and save distinct name for later sync
+  my %existing_images;
+  foreach my $img (@upload_img) {
+    die $::locale->text("Need a image title") unless $img->{description};
+    my $distinct_media_name = $partnumber . '_' . $img->{description};
+    $existing_images{$distinct_media_name} = 1;
+    my $image_filter = {  'filter' => [
+                          {
+                            'value' => $distinct_media_name,
+                            'type'  => 'equals',
+                            'field' => 'fileName'
+                          }
+                        ]
+                      };
+    $ret           = $self->connector->POST('api/search/media', to_json($image_filter));
+    $response_code = $ret->responseCode();
+    die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 200;
+    my $current_image_id; # maybe empty
+    try {
+      $current_image_id = from_json($ret->responseContent())->{data}->[0]->{id};
+    } catch { die "Malformed JSON Data: $_ " . $ret->responseContent();  };
+
+    # 2.1 no image with this title, create metadata for media and upload image
+    if (!$current_image_id) {
+      # not yet uploaded, create media entry
+      $ret = $self->connector->POST("/api/media?_response=true");
+      $response_code = $ret->responseCode();
+      die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 200;
+      try {
+        $current_image_id = from_json($ret->responseContent())->{data}{id};
+      } catch { die "Malformed JSON Data: $_ " . $ret->responseContent();  };
+    }
+    # 2.2 update the image data (current_image_id was found or created)
+    $ret = $self->connector->POST("/api/_action/media/$current_image_id/upload?fileName=$distinct_media_name&extension=$img->{extension}",
+                                    $img->{link},
+                                   {
+                                    "Content-Type"  => "image/$img->{extension}",
+                                   });
+    $response_code = $ret->responseCode();
+    die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 204;
+
+    # 2.3 check if a product media entry exists for this id
+    my $product_media_filter = {
+              'filter' => [
+                        {
+                          'value' => $product_id,
+                          'type' => 'equals',
+                          'field' => 'productId'
+                        },
+                        {
+                          'value' => $current_image_id,
+                          'type' => 'equals',
+                          'field' => 'mediaId'
+                        },
+                      ]
+        };
+    $ret = $self->connector->POST('api/search/product-media', to_json($product_media_filter));
+    $response_code = $ret->responseCode();
+    die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 200;
+    my ($has_product_media, $product_media_id);
+    try {
+      $has_product_media = from_json($ret->responseContent())->{total};
+      $product_media_id  = from_json($ret->responseContent())->{data}->[0]->{id};
+    } catch { die "Malformed JSON Data: $_ " . $ret->responseContent();  };
+
+    # 2.4 ... and either update or create the entry
+    #     set shopware position to kivi position
+    my $product_media;
+    $product_media->{position} = $img->{position}; # position may change
+
+    if ($has_product_media == 0) {
+      # 2.4.1 new entry. link product to media
+      $product_media->{productId} = $product_id;
+      $product_media->{mediaId}   = $current_image_id;
+      $ret = $self->connector->POST('api/product-media', to_json($product_media));
+    } elsif ($has_product_media == 1 && $product_media_id) {
+      $ret = $self->connector->PATCH("api/product-media/$product_media_id", to_json($product_media));
+    } else {
+      die "Invalid state, please inform Shopware master admin at product-media filter: $product_media_filter";
+    }
+    $response_code = $ret->responseCode();
+    die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 204;
+  }
+  # 3. optional set image with position 1 as cover image
+  if ($params{set_cover}) {
+    # set cover if position == 1
+    my $product_media_filter = {
+              'filter' => [
+                        {
+                          'value' => $product_id,
+                          'type' => 'equals',
+                          'field' => 'productId'
+                        },
+                        {
+                          'value' => '1',
+                          'type' => 'equals',
+                          'field' => 'position'
+                        },
+                          ]
+                             };
+
+    $ret = $self->connector->POST('api/search/product-media', to_json($product_media_filter));
+    $response_code = $ret->responseCode();
+    die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 200;
+    my $cover;
+    try {
+      $cover->{coverId} = from_json($ret->responseContent())->{data}->[0]->{id};
+    } catch { die "Malformed JSON Data: $_ " . $ret->responseContent();  };
+    $ret = $self->connector->PATCH('api/product/' . $product_id, to_json($cover));
+    $response_code = $ret->responseCode();
+    die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 204;
+  }
+  # 4. optional delete orphaned images in shopware
+  if ($params{delete_orphaned}) {
+    # delete orphaned images
+    my $product_media_filter = {
+              'filter' => [
+                        {
+                          'value' => $product_id,
+                          'type' => 'equals',
+                          'field' => 'productId'
+                        }, ] };
+    $ret = $self->connector->POST('api/search/product-media', to_json($product_media_filter));
+    $response_code = $ret->responseCode();
+    die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 200;
+    my $img_ary;
+    try {
+      $img_ary = from_json($ret->responseContent())->{data};
+    } catch { die "Malformed JSON Data: $_ " . $ret->responseContent();  };
+
+    if (scalar @{ $img_ary} > 0) { # maybe no images at all
+      my %existing_img;
+      $existing_img{$_->{media}->{fileName}}= $_->{media}->{id} for @{ $img_ary };
+
+      while (my ($name, $id) = each %existing_img) {
+        next if $existing_images{$name};
+        $ret = $self->connector->DELETE("api/media/$id");
+        $response_code = $ret->responseCode();
+        die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code == 204;
+      }
+    }
+  }
+  return;
+}
+
+sub get_categories {
+  my ($self) = @_;
+
+  my $ret           = $self->connector->POST('api/search/category');
+  my $response_code = $ret->responseCode();
+
+  die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code eq '200';
+
+  my $import;
+  try {
+    $import = decode_json $ret->responseContent();
+  } catch {
+    die "Malformed JSON Data: $_ " . $ret->responseContent();
+  };
+
+  my @daten      = @{ $import->{data} };
+  my %categories = map { ($_->{id} => $_) } @daten;
+
+  my @categories_tree;
+  for (@daten) {
+    my $parent = $categories{$_->{parentId}};
+    if ($parent) {
+      $parent->{children} ||= [];
+      push @{ $parent->{children} }, $_;
+    } else {
+      push @categories_tree, $_;
+    }
+  }
+  return \@categories_tree;
+}
+
+sub get_one_order  {
+  my ($self, $ordnumber) = @_;
+
+  croak t8("No Order Number") unless $ordnumber;
+  # set known params for the return structure
+  my %fetched_order  = $self->get_fetched_order_structure;
+  my $assoc          = $self->all_open_orders();
+
+  # overwrite filter for exactly one ordnumber
+  $assoc->{filter}->[0]->{value} = $ordnumber;
+  $assoc->{filter}->[0]->{type}  = 'equals';
+  $assoc->{filter}->[0]->{field} = 'orderNumber';
+
+  # 1. fetch the order and import it as a kivi order
+  # 2. return the number of processed order (1)
+  my $one_order = $self->connector->POST('api/search/order', to_json($assoc));
+
+  # 1. check for bad request or connection problems
+  if ($one_order->responseCode() != 200) {
+    $fetched_order{error}   = 1;
+    $fetched_order{message} = $one_order->responseCode() . ' ' . $one_order->responseContent();
+    return \%fetched_order;
+  }
+
+  # 1.1 parse json or exit
+  my $content;
+  try {
+    $content = from_json($one_order->responseContent());
+  } catch {
+    $fetched_order{error}   = 1;
+    $fetched_order{message} = "Malformed JSON Data: $_ " . $one_order->responseContent();
+    return \%fetched_order;
+  };
+
+  # 2. check if we found ONE order at all
+  my $total = $content->{total};
+  if ($total == 0) {
+    $fetched_order{number_of_orders} = 0;
+    return \%fetched_order;
+  } elsif ($total != 1) {
+    $fetched_order{error}   = 1;
+    $fetched_order{message} = "More than one Order returned. Invalid State: $total";
+    return \%fetched_order;
+  }
+
+  # 3. there is one valid order, try to import this one
+  if ($self->import_data_to_shop_order($content->{data}->[0])) {
+    %fetched_order = (shop_description => $self->config->description, number_of_orders => 1);
+  } else {
+    $fetched_order{message} = "Error: $@";
+    $fetched_order{error}   = 1;
+  }
+  return \%fetched_order;
+}
+
+sub get_new_orders {
+  my ($self) = @_;
+
+  my %fetched_order  = $self->get_fetched_order_structure;
+  my $assoc          = $self->all_open_orders();
+
+  # 1. fetch all open orders and try to import it as a kivi order
+  # 2. return the number of processed order $total
+  my $open_orders = $self->connector->POST('api/search/order', to_json($assoc));
+
+  # 1. check for bad request or connection problems
+  if ($open_orders->responseCode() != 200) {
+    $fetched_order{error}   = 1;
+    $fetched_order{message} = $open_orders->responseCode() . ' ' . $open_orders->responseContent();
+    return \%fetched_order;
+  }
+
+  # 1.1 parse json or exit
+  my $content;
+  try {
+    $content = from_json($open_orders->responseContent());
+  } catch {
+    $fetched_order{error}   = 1;
+    $fetched_order{message} = "Malformed JSON Data: $_ " . $open_orders->responseContent();
+    return \%fetched_order;
+  };
+
+  # 2. check if we found one or more order at all
+  my $total = $content->{total};
+  if ($total == 0) {
+    $fetched_order{number_of_orders} = 0;
+    return \%fetched_order;
+  } elsif (!$total || !($total > 0)) {
+    $fetched_order{error}   = 1;
+    $fetched_order{message} = "Undefined value for total orders returned. Invalid State: $total";
+    return \%fetched_order;
+  }
+
+  # 3. there are open orders. try to import one by one
+  $fetched_order{number_of_orders} = 0;
+  foreach my $open_order (@{ $content->{data} }) {
+    if ($self->import_data_to_shop_order($open_order)) {
+      $fetched_order{number_of_orders}++;
+    } else {
+      $fetched_order{message} .= "Error at importing order with running number:"
+                                  . $fetched_order{number_of_orders}+1 . ": $@ \n";
+      $fetched_order{error}    = 1;
+    }
+  }
+  return \%fetched_order;
+}
+
+sub get_article {
+  my ($self, $partnumber) = @_;
+
+  $partnumber   = $::form->escape($partnumber);
+  my $product_filter = {
+              'filter' => [
+                            {
+                              'value' => $partnumber,
+                              'type' => 'equals',
+                              'field' => 'productNumber'
+                            }
+                          ]
+                       };
+  my $ret = $self->connector->POST('api/search/product', to_json($product_filter));
+
+  my $response_code = $ret->responseCode();
+  die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code eq '200';
+
+  my $data_json;
+  try {
+    $data_json = decode_json $ret->responseContent();
+  } catch {
+    die "Malformed JSON Data: $_ " . $ret->responseContent();
+  };
+
+  # maybe no product was found ...
+  return undef unless scalar @{ $data_json->{data} } > 0;
+  # caller wants this structure:
+  # $stock_onlineshop = $shop_article->{data}->{mainDetail}->{inStock};
+  # $active_online = $shop_article->{data}->{active};
+  my $data;
+  $data->{data}->{mainDetail}->{inStock} = $data_json->{data}->[0]->{stock};
+  $data->{data}->{active}                = $data_json->{data}->[0]->{active};
+  return $data;
+}
+
+sub get_version {
+  my ($self) = @_;
+
+  my $return  = {}; # return for caller
+  my $ret     = {}; # internal return
+
+  #  1. check if we can connect at all
+  #  2. request version number
+
+  $ret = $self->connector;
+  if (200 != $ret->responseCode()) {
+    $return->{success}         = 0;
+    $return->{data}->{version} = $self->{errors}; # whatever init puts in errors
+    return $return;
+  }
+
+  $ret = $self->connector->GET('api/_info/version');
+  if (200 == $ret->responseCode()) {
+    my $version = from_json($self->connector->responseContent())->{version};
+    $return->{success}         = 1;
+    $return->{data}->{version} = $version;
+  } else {
+    $return->{success}         = 0;
+    $return->{data}->{version} = $ret->responseContent(); # Whatever REST Interface says
+  }
+
+  return $return;
+}
+
+sub set_orderstatus {
+  my ($self, $order_id, $transition) = @_;
+
+  # one state differs
+  $transition = 'complete' if $transition eq 'completed';
+
+  croak "No shop order ID, should be in format [0-9a-f]{32}" unless $order_id   =~ m/^[0-9a-f]{32}$/;
+  croak "NO valid transition value"                          unless $transition =~ m/(open|process|cancel|complete)/;
+  my $ret;
+  $ret = $self->connector->POST("/api/_action/order/$order_id/state/$transition");
+  my $response_code = $ret->responseCode();
+  die "Request failed, response code was: $response_code\n" . $ret->responseContent() unless $response_code eq '200';
+
+}
+
+sub init_connector {
+  my ($self) = @_;
+
+  my $protocol = $self->config->server =~ /(^https:\/\/|^http:\/\/)/ ? '' : $self->config->protocol . '://';
+  my $client   = REST::Client->new(host => $protocol . $self->config->server);
+
+  $client->getUseragent()->proxy([$self->config->protocol], $self->config->proxy) if $self->config->proxy;
+  $client->addHeader('Content-Type', 'application/json');
+  $client->addHeader('charset',      'UTF-8');
+  $client->addHeader('Accept',       'application/json');
+
+  my %auth_req = (
+                   client_id     => $self->config->login,
+                   client_secret => $self->config->password,
+                   grant_type    => "client_credentials",
+                 );
+
+  my $ret = $client->POST('/api/oauth/token', encode_json(\%auth_req));
+
+  unless (200 == $ret->responseCode()) {
+    $self->{errors} .= $ret->responseContent();
+    return;
+  }
+
+  my $token = from_json($client->responseContent())->{access_token};
+  unless ($token) {
+    $self->{errors} .= "No Auth-Token received";
+    return;
+  }
+  # persist refresh token
+  $client->addHeader('Authorization' => 'Bearer ' . $token);
+  return $client;
+}
+
+sub import_data_to_shop_order {
+  my ($self, $import) = @_;
+
+  # failsafe checks for not yet implemented
+  die t8('Shipping cost article not implemented') if $self->config->shipping_costs_parts_id;
+
+  # no mapping unless we also have at least one shop order item ...
+  my $order_pos = delete $import->{lineItems};
+  croak t8("No Order items fetched") unless ref $order_pos eq 'ARRAY';
+
+  my $shop_order = $self->map_data_to_shoporder($import);
+
+  my $shop_transaction_ret = $shop_order->db->with_transaction(sub {
+    $shop_order->save;
+    my $id = $shop_order->id;
+
+    my @positions = sort { Sort::Naturally::ncmp($a->{"label"}, $b->{"label"}) } @{ $order_pos };
+    my $position = 0;
+    my $active_price_source = $self->config->price_source;
+    #Mapping Positions
+    foreach my $pos (@positions) {
+      $position++;
+      my $price       = $::form->round_amount($pos->{unitPrice}, 2); # unit
+      my %pos_columns = ( description          => $pos->{product}->{name},
+                          partnumber           => $pos->{product}->{productNumber},
+                          price                => $price,
+                          quantity             => $pos->{quantity},
+                          position             => $position,
+                          tax_rate             => $pos->{priceDefinition}->{taxRules}->[0]->{taxRate},
+                          shop_trans_id        => $pos->{id}, # pos id or shop_trans_id ? or dont care?
+                          shop_order_id        => $id,
+                          active_price_source  => $active_price_source,
+                        );
+      my $pos_insert = SL::DB::ShopOrderItem->new(%pos_columns);
+      $pos_insert->save;
+    }
+    $shop_order->positions($position);
+
+    if ( $self->config->shipping_costs_parts_id ) {
+      die t8("Not yet implemented");
+      # TODO NOT YET Implemented nor tested, this is shopware5 code:
+      my $shipping_part = SL::DB::Part->find_by( id => $self->config->shipping_costs_parts_id);
+      my %shipping_pos = ( description    => $import->{data}->{dispatch}->{name},
+                           partnumber     => $shipping_part->partnumber,
+                           price          => $import->{data}->{invoiceShipping},
+                           quantity       => 1,
+                           position       => $position,
+                           shop_trans_id  => 0,
+                           shop_order_id  => $id,
+                         );
+      my $shipping_pos_insert = SL::DB::ShopOrderItem->new(%shipping_pos);
+      $shipping_pos_insert->save;
+    }
+
+    my $customer = $shop_order->get_customer;
+
+    if (ref $customer eq 'SL::DB::Customer') {
+      $shop_order->kivi_customer_id($customer->id);
+    }
+    $shop_order->save;
+
+    # update state in shopware before transaction ends
+    $self->set_orderstatus($shop_order->shop_trans_id, "process");
+
+    1;
+
+  }) || die t8('Error while saving shop order #1. DB Error #2. Generic exception #3.',
+                $shop_order->{shop_ordernumber}, $shop_order->db->error, $@);
+}
+
+sub map_data_to_shoporder {
+  my ($self, $import) = @_;
+
+  croak "Expect a hash with one order." unless ref $import eq 'HASH';
+  # we need one number and a order date, some total prices and one customer
+  croak "Does not look like a shopware6 order" unless    $import->{orderNumber}
+                                                      && $import->{orderDateTime}
+                                                      && ref $import->{price} eq 'HASH'
+                                                      && ref $import->{orderCustomer} eq 'HASH';
+
+  my $shipto_id = $import->{deliveries}->[0]->{shippingOrderAddressId};
+  die t8("Cannot get shippingOrderAddressId for #1", $import->{orderNumber}) unless $shipto_id;
+
+  my $billing_ary = [ grep { $_->{id} == $import->{billingAddressId} }       @{ $import->{addresses} } ];
+  my $shipto_ary  = [ grep { $_->{id} == $shipto_id }                        @{ $import->{addresses} } ];
+  my $payment_ary = [ grep { $_->{id} == $import->{paymentMethodId} }        @{ $import->{paymentMethods} } ];
+
+  die t8("No Billing and ship to address, for Order Number #1 with ID Billing #2 and ID Shipping #3",
+          $import->{orderNumber}, $import->{billingAddressId}, $import->{deliveries}->[0]->{shippingOrderAddressId})
+    unless scalar @{ $billing_ary } == 1 && scalar @{ $shipto_ary } == 1;
+
+  my $billing = $billing_ary->[0];
+  my $shipto  = $shipto_ary->[0];
+  # TODO payment info is not used at all
+  my $payment = scalar @{ $payment_ary } ? delete $payment_ary->[0] : undef;
+
+  # check mandatory fields from shopware
+  die t8("No billing city")   unless $billing->{city};
+  die t8("No shipto city")    unless $shipto->{city};
+  die t8("No customer email") unless $import->{orderCustomer}->{email};
+
+  # extract order date
+  my $parser = DateTime::Format::Strptime->new(pattern   => '%Y-%m-%dT%H:%M:%S',
+                                               locale    => 'de_DE',
+                                               time_zone => 'local'             );
+  my $orderdate;
+  try {
+    $orderdate = $parser->parse_datetime($import->{orderDateTime});
+  } catch { die "Cannot parse Order Date" . $_ };
+
+  my $shop_id      = $self->config->id;
+  my $tax_included = $self->config->pricetype;
+
+  # TODO copied from shopware5 connector
+  # Mapping Zahlungsmethoden muss an Firmenkonfiguration angepasst werden
+  my %payment_ids_methods = (
+    # shopware_paymentId => kivitendo_payment_id
+  );
+  my $default_payment    = SL::DB::Manager::PaymentTerm->get_first();
+  my $default_payment_id = $default_payment ? $default_payment->id : undef;
+  #
+
+
+  my %columns = (
+    amount                  => $import->{amountTotal},
+    billing_city            => $billing->{city},
+    billing_company         => $billing->{company},
+    billing_country         => $billing->{country}->{name},
+    billing_department      => $billing->{department},
+    billing_email           => $import->{orderCustomer}->{email},
+    billing_fax             => $billing->{fax},
+    billing_firstname       => $billing->{firstName},
+    #billing_greeting        => ($import->{billing}->{salutation} eq 'mr' ? 'Herr' : 'Frau'),
+    billing_lastname        => $billing->{lastName},
+    billing_phone           => $billing->{phone},
+    billing_street          => $billing->{street},
+    billing_vat             => $billing->{vatId},
+    billing_zipcode         => $billing->{zipcode},
+    customer_city           => $billing->{city},
+    customer_company        => $billing->{company},
+    customer_country        => $billing->{country}->{name},
+    customer_department     => $billing->{department},
+    customer_email          => $billing->{email},
+    customer_fax            => $billing->{fax},
+    customer_firstname      => $billing->{firstName},
+    #customer_greeting       => ($billing}->{salutation} eq 'mr' ? 'Herr' : 'Frau'),
+    customer_lastname       => $billing->{lastName},
+    customer_phone          => $billing->{phoneNumber},
+    customer_street         => $billing->{street},
+    customer_vat            => $billing->{vatId},
+    customer_zipcode        => $billing->{zipcode},
+#    customer_newsletter     => $customer}->{newsletter},
+    delivery_city           => $shipto->{city},
+    delivery_company        => $shipto->{company},
+    delivery_country        => $shipto->{country}->{name},
+    delivery_department     => $shipto->{department},
+    delivery_email          => "",
+    delivery_fax            => $shipto->{fax},
+    delivery_firstname      => $shipto->{firstName},
+    #delivery_greeting       => ($shipto}->{salutation} eq 'mr' ? 'Herr' : 'Frau'),
+    delivery_lastname       => $shipto->{lastName},
+    delivery_phone          => $shipto->{phone},
+    delivery_street         => $shipto->{street},
+    delivery_vat            => $shipto->{vatId},
+    delivery_zipcode        => $shipto->{zipCode},
+#    host                    => $shop}->{hosts},
+    netamount               => $import->{amountNet},
+    order_date              => $orderdate,
+    payment_description     => $payment->{name},
+    payment_id              => $payment_ids_methods{$import->{paymentId}} || $default_payment_id,
+    tax_included            => $tax_included eq "brutto" ? 1 : 0,
+    shop_ordernumber        => $import->{orderNumber},
+    shop_id                 => $shop_id,
+    shop_trans_id           => $import->{id},
+    # TODO map these:
+    #remote_ip               => $import->{remoteAddress},
+    #sepa_account_holder     => $import->{paymentIntances}->{accountHolder},
+    #sepa_bic                => $import->{paymentIntances}->{bic},
+    #sepa_iban               => $import->{paymentIntances}->{iban},
+    #shipping_costs          => $import->{invoiceShipping},
+    #shipping_costs_net      => $import->{invoiceShippingNet},
+    #shop_c_billing_id       => $import->{billing}->{customerId},
+    #shop_c_billing_number   => $import->{billing}->{number},
+    #shop_c_delivery_id      => $import->{shipping}->{id},
+    #shop_customer_id        => $import->{customerId},
+    #shop_customer_number    => $import->{billing}->{number},
+    #shop_customer_comment   => $import->{customerComment},
+  );
+
+  my $shop_order = SL::DB::ShopOrder->new(%columns);
+  return $shop_order;
+}
+
+sub _u8 {
+  my ($value) = @_;
+  return encode('UTF-8', $value // '');
+}
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+  SL::ShopConnector::Shopware6 - this is the Connector Class for Shopware 6
+
+=head1 SYNOPSIS
+
+
+=head1 DESCRIPTION
+
+=head1 AVAILABLE METHODS
+
+=over 4
+
+=item C<get_one_order>
+
+=item C<get_new_orders>
+
+=item C<update_part>
+
+Updates all metadata for a shop part. See base class for a general description.
+Specific Implementation notes:
+=over 4
+
+=item Calls sync_all_images with set_cover = 1 and delete_orphaned = 1
+
+=item Checks if longdescription should be taken from part or shop_part
+
+=item Checks if a language with the name 'Englisch' or template_code 'en'
+      is available and sets the shopware6 'en-GB' locales for the product
+
+=item C<sync_all_images (set_cover: 0|1, delete_orphaned: 0|1)>
+
+The connecting key for shopware to kivi images is the image name.
+To get distinct entries the kivi partnumber is combined with the title (description)
+of the image. Therefore part1000_someTitlefromUser should be unique in
+Shopware.
+All image data is simply send to shopware whether or not image data
+has been edited recently.
+If set_cover is set, the image with the position 1 will be used as
+the shopware cover image.
+If delete_orphaned ist set, all images related to the shopware product
+which are not also in kivitendo will be deleted.
+Shopware (6.4.x) takes care of deleting all the relations if the media
+entry for the image is deleted.
+More on media and Shopware6 can be found here:
+https://shopware.stoplight.io/docs/admin-api/ZG9jOjEyNjI1Mzkw-media-handling
+
+=back
+
+=over 4
+
+=item C<get_article>
+
+=item C<get_categories>
+
+=item C<get_version>
+
+Tries to establish a connection and in a second step
+tries to get the server's version number.
+Returns a hashref with the data structure the Base class expects.
+
+=item C<set_orderstatus>
+
+=item C<init_connector>
+
+Inits the connection to the REST Server.
+Errors are collected in $self->{errors} and undef will be returned.
+If successful returns a REST::Client object for further communications.
+
+=back
+
+=head1 SEE ALSO
+
+L<SL::ShopConnector::ALL>
+
+=head1 BUGS
+
+None yet. :)
+
+=head1 TODOS
+
+=over 4
+
+=item * Map all data to shop_order
+
+Missing fields are commented in the sub map_data_to_shoporder.
+Some items are SEPA debit info, IP adress, delivery costs etc
+Furthermore Shopware6 uses currency, country and locales information.
+Detailed list:
+
+    #customer_newsletter     => $customer}->{newsletter},
+    #remote_ip               => $import->{remoteAddress},
+    #sepa_account_holder     => $import->{paymentIntances}->{accountHolder},
+    #sepa_bic                => $import->{paymentIntances}->{bic},
+    #sepa_iban               => $import->{paymentIntances}->{iban},
+    #shipping_costs          => $import->{invoiceShipping},
+    #shipping_costs_net      => $import->{invoiceShippingNet},
+    #shop_c_billing_id       => $import->{billing}->{customerId},
+    #shop_c_billing_number   => $import->{billing}->{number},
+    #shop_c_delivery_id      => $import->{shipping}->{id},
+    #shop_customer_id        => $import->{customerId},
+    #shop_customer_number    => $import->{billing}->{number},
+    #shop_customer_comment   => $import->{customerComment},
+
+=item * Use shipping_costs_parts_id for additional shipping costs
+
+Currently dies if a shipping_costs_parts_id is set in the config
+
+=item * Payment Infos can be read from shopware but is not linked with kivi
+
+Unused data structures in sub map_data_to_shoporder => payment_ary
+
+=item * Delete orphaned images is new in this connector, but should be in a separate method
+
+=item * Fetch from last order number is ignored and should not be needed
+
+Fetch orders also sets the state of the order from open to process. The state setting
+is transaction safe and therefore get_new_orders should always fetch only unprocessed orders
+at all. Nevertheless get_one_order just gets one order with the exactly matching order number
+and ignores any shopware order transition state.
+
+=item * Get one order and get new orders is basically the same except for the filter
+
+Right now the returning structure and the common parts of the filter are in two separate functions
+
+=item * Locales!
+
+Many error messages are thrown, but at least the more common cases should be localized.
+
+=item * Multi language support
+
+By guessing the correct german name for the english language some translation for parts can
+also be synced. This should be more clear (language configuration for shops) and the order
+synchronisation should also handle this (longdescription is simply copied from part.notes)
+
+=back
+
+=head1 AUTHOR
+
+Jan Büren jan@kivitendo.de
+
+=cut
index 8682c7e..b20a7b1 100644 (file)
@@ -47,7 +47,7 @@ sub available_templates {
        -d ($::lx_office_conf{paths}->{templates} . "/$_")
     && !/^\.\.?$/
     && !m/\.(?:html|tex|sty|odt)$/
-    && !m/^(?:webpages$|print$|mail$|\.)/
+    && !m/^(?:webpages$|mobile_webpages$|pdf$|print$|mail$|\.)/
   } keys %dir_h;
 
   tie %dir_h, 'IO::Dir', "$::lx_office_conf{paths}->{templates}/print";
index e570321..66d8f83 100644 (file)
@@ -6,15 +6,21 @@ use Archive::Zip;
 use Encode;
 use HTML::Entities;
 use POSIX 'setsid';
+use XML::LibXML;
 
 use SL::Iconv;
 use SL::Template::OpenDocument::Styles;
 
+use SL::DB::BankAccount;
+use SL::Helper::QrBill;
+use SL::Helper::ISO3166;
+
 use Cwd;
 # use File::Copy;
 # use File::Spec;
 # use File::Temp qw(:mktemp);
 use IO::File;
+use List::Util qw(first);
 
 use strict;
 
@@ -346,11 +352,20 @@ sub parse_block {
 sub parse {
   $main::lxdebug->enter_sub();
   my $self = $_[0];
+
   local *OUT = $_[1];
   my $form = $self->{"form"};
 
   close(OUT);
 
+  my $qr_image_path;
+  if ($::instance_conf->get_create_qrbill_invoices && $form->{formname} eq 'invoice') {
+    # the biller account information, biller address and the reference number,
+    # are needed in the template aswell as in the qr-code generation, therefore
+    # assemble these and add to $::form
+    $qr_image_path = $self->generate_qr_code;
+  }
+
   my $file_name;
   if ($form->{"IN"} =~ m|^/|) {
     $file_name = $form->{"IN"};
@@ -420,6 +435,28 @@ sub parse {
     $zip->contents("styles.xml", Encode::encode('utf-8-strict', $new_styles));
   }
 
+  if ($::instance_conf->get_create_qrbill_invoices && $form->{formname} eq 'invoice') {
+    # get placeholder path from odt XML
+    my $qr_placeholder_path;
+    my $dom = XML::LibXML->load_xml(string => $contents);
+    my @nodelist = $dom->getElementsByTagName("draw:frame");
+    for my $node (@nodelist) {
+      my $attr = $node->getAttribute('draw:name');
+      if ($attr eq 'QRCodePlaceholder') {
+        my @children = $node->getChildrenByTagName('draw:image');
+        $qr_placeholder_path = $children[0]->getAttribute('xlink:href');
+      }
+    }
+    if (!defined($qr_placeholder_path)) {
+      $::form->error($::locale->text('QR-Code placeholder image: QRCodePlaceholder not found in template.'));
+    }
+    # replace QR-Code Placeholder Image in zip file (odt) with generated one
+    $zip->updateMember(
+     $qr_placeholder_path,
+     $qr_image_path
+    );
+  }
+
   $zip->writeToFileNamed($form->{"tmpfile"}, 1);
 
   my $res = 1;
@@ -431,6 +468,276 @@ sub parse {
   return $res;
 }
 
+sub get_qrbill_account {
+  $main::lxdebug->enter_sub();
+  my ($self) = @_;
+
+  my $qr_account;
+
+  my $bank_accounts     = SL::DB::Manager::BankAccount->get_all;
+  $qr_account = scalar(@{ $bank_accounts }) == 1 ?
+    $bank_accounts->[0] :
+    first { $_->use_for_qrbill } @{ $bank_accounts };
+
+  if (!$qr_account) {
+    $::form->error($::locale->text('No bank account flagged for QRBill usage was found.'));
+  }
+
+  $main::lxdebug->leave_sub();
+  return $qr_account;
+}
+
+sub remove_letters_prefix {
+  my $s = $_[0];
+  $s =~ s/^[a-zA-Z]+//;
+  return $s;
+}
+
+sub check_digits_and_max_length {
+  my $s = $_[0];
+  my $length = $_[1];
+
+  return 0 if (!($s =~ /^\d*$/) || length($s) > $length);
+  return 1;
+}
+
+sub calculate_check_digit {
+  # calculate ESR check digit using algorithm: "modulo 10, recursive"
+  my $ref_number_str = $_[0];
+
+  my @m = (0, 9, 4, 6, 8, 2, 7, 1, 3, 5);
+  my $carry = 0;
+
+  my @ref_number_split = map int($_), split(//, $ref_number_str);
+
+  for my $v (@ref_number_split) {
+    $carry = @m[($carry + $v) % 10];
+  }
+
+  return (10 - $carry) % 10;
+}
+
+sub assemble_ref_number {
+  $main::lxdebug->enter_sub();
+
+  my $bank_id = $_[0];
+  my $customer_number = $_[1];
+  my $order_number = $_[2] // "0";
+  my $invoice_number = $_[3] // "0";
+
+  # check values (analog to checks in makro)
+  # - bank_id
+  #     input: 6 digits, only numbers
+  #     output: 6 digits, only numbers
+  if (!($bank_id =~ /^\d*$/) || length($bank_id) != 6) {
+    $::form->error($::locale->text('Bank account id number invalid. Must be 6 digits.'));
+  }
+
+  # - customer_number
+  #     input: prefix (letters) + up to 6 digits (numbers)
+  #     output: prefix removed, 6 digits, filled with leading zeros
+  $customer_number = remove_letters_prefix($customer_number);
+  if (!check_digits_and_max_length($customer_number, 6)) {
+    $::form->error($::locale->text('Customer number invalid. Must be less then or equal to 6 digits after prefix.'));
+  }
+  # fill with zeros
+  $customer_number = sprintf "%06d", $customer_number;
+
+  # - order_number
+  #     input: prefix (letters) + up to 7 digits, may be zero
+  #     output: prefix removed, 7 digits, filled with leading zeros
+  $order_number = remove_letters_prefix($order_number);
+  if (!check_digits_and_max_length($order_number, 7)) {
+    $::form->error($::locale->text('Order number invalid. Must be less then or equal to 7 digits after prefix.'));
+  }
+  # fill with zeros
+  $order_number = sprintf "%07d", $order_number;
+
+  # - invoice_number
+  #     input: prefix (letters) + up to 7 digits, may be zero
+  #     output: prefix removed, 7 digits, filled with leading zeros
+  $invoice_number = remove_letters_prefix($invoice_number);
+  if (!check_digits_and_max_length($invoice_number, 7)) {
+    $::form->error($::locale->text('Invoice number invalid. Must be less then or equal to 7 digits after prefix.'));
+  }
+  # fill with zeros
+  $invoice_number = sprintf "%07d", $invoice_number;
+
+  # assemble ref. number
+  my $ref_number = $bank_id . $customer_number . $order_number . $invoice_number;
+
+  # calculate check digit
+  my $ref_number_cpl = $ref_number . calculate_check_digit($ref_number);
+
+  $main::lxdebug->leave_sub();
+  return $ref_number_cpl;
+}
+
+sub get_ref_number_formatted {
+  $main::lxdebug->enter_sub();
+
+  my $ref_number = $_[0];
+
+  # create ref. number in format:
+  # 'XX XXXXX XXXXX XXXXX XXXXX XXXXX' (2 digits + 5 x 5 digits)
+  my $ref_number_spaced = substr($ref_number, 0, 2) . ' ' .
+                          substr($ref_number, 2, 5) . ' ' .
+                          substr($ref_number, 7, 5) . ' ' .
+                          substr($ref_number, 12, 5) . ' ' .
+                          substr($ref_number, 17, 5) . ' ' .
+                          substr($ref_number, 22, 5);
+
+  $main::lxdebug->leave_sub();
+  return $ref_number_spaced;
+}
+
+sub get_iban_formatted {
+  $main::lxdebug->enter_sub();
+
+  my $iban = $_[0];
+
+  # create iban number in format:
+  # 'XXXX XXXX XXXX XXXX XXXX X' (5 x 4 + 1digits)
+  my $iban_spaced = substr($iban, 0, 4) . ' ' .
+                    substr($iban, 4, 4) . ' ' .
+                    substr($iban, 8, 4) . ' ' .
+                    substr($iban, 12, 4) . ' ' .
+                    substr($iban, 16, 4) . ' ' .
+                    substr($iban, 20, 1);
+
+  $main::lxdebug->leave_sub();
+  return $iban_spaced;
+}
+
+sub get_amount_formatted {
+  $main::lxdebug->enter_sub();
+
+  unless ($_[0] =~ /^\d+\.\d{2}$/) {
+    $::form->error($::locale->text('Amount has wrong format.'));
+  }
+
+  local $_ = shift;
+  $_ = reverse split //;
+  m/^\d{2}\./g;
+  s/\G(\d{3})(?=\d)/$1 /g;
+
+  $main::lxdebug->leave_sub();
+  return scalar reverse split //;
+}
+
+sub generate_qr_code {
+  $main::lxdebug->enter_sub();
+  my $self = $_[0];
+  my $form = $self->{"form"};
+
+  # assemble data for QR-Code
+
+  # get qr-account data
+  my $qr_account = $self->get_qrbill_account();
+
+  my %biller_information = (
+    'iban' => $qr_account->{'iban'}
+  );
+
+  my $biller_countrycode = SL::Helper::ISO3166::map_name_to_alpha_2_code(
+    $::instance_conf->get_address_country()
+  );
+  if (!$biller_countrycode) {
+    $::form->error($::locale->text('Error mapping biller countrycode.'));
+  }
+  my %biller_data = (
+    'address_type' => 'K',
+    'company' => $::instance_conf->get_company(),
+    'address_row1' => $::instance_conf->get_address_street1(),
+    'address_row2' => $::instance_conf->get_address_zipcode() . ' ' . $::instance_conf->get_address_city(),
+    'countrycode' => $biller_countrycode,
+  );
+
+  my $amount;
+  if ($form->{'qrbill_without_amount'}) {
+    $amount = '';
+  } else {
+    $amount = sprintf("%.2f", $form->parse_amount(\%::myconfig, $form->{'total'}));
+  }
+
+  my %payment_information = (
+    'amount' => $amount,
+    'currency' => $form->{'currency'},
+  );
+
+  my $customer_countrycode = SL::Helper::ISO3166::map_name_to_alpha_2_code($form->{'country'});
+  if (!$customer_countrycode) {
+    $::form->error($::locale->text('Error mapping customer countrycode.'));
+  }
+  my %invoice_recipient_data = (
+    'address_type' => 'K',
+    'name' => $form->{'name'},
+    'address_row1' => $form->{'street'},
+    'address_row2' => $form->{'zipcode'} . ' ' . $form->{'city'},
+    'countrycode' => $customer_countrycode,
+  );
+
+  my %ref_nr_data;
+  if ($::instance_conf->get_create_qrbill_invoices == 1) {
+    # generate ref.-no. with check digit
+    my $ref_number = assemble_ref_number(
+      $qr_account->{'bank_account_id'},
+      $form->{'customernumber'},
+      $form->{'ordnumber'},
+      $form->{'invnumber'},
+    );
+    %ref_nr_data = (
+      'type' => 'QRR',
+      'ref_number' => $ref_number,
+    );
+    # get ref. number/iban formatted with spaces and set into form for template
+    # processing
+    $form->{'ref_number'} = $ref_number;
+    $form->{'ref_number_formatted'} = get_ref_number_formatted($ref_number);
+  } elsif ($::instance_conf->get_create_qrbill_invoices == 2) {
+    %ref_nr_data = (
+      'type' => 'NON',
+      'ref_number' => '',
+    );
+  } else {
+    $::form->error($::locale->text('Error getting QR-Bill type.'));
+  }
+
+  # set into form for template processing
+  $form->{'biller_information'} = \%biller_information;
+  $form->{'biller_data'} = \%biller_data;
+  $form->{'iban_formatted'} = get_iban_formatted($qr_account->{'iban'});
+
+  # format amount for template
+  $form->{'amount_formatted'} = get_amount_formatted(
+    sprintf(
+      "%.2f",
+      $form->parse_amount(\%::myconfig, $form->{'total'})
+    )
+  );
+
+  # set outfile
+  my $outfile = $form->{"tmpdir"} . '/' . 'qr-code.png';
+
+  # generate QR-Code Image
+  eval {
+   my $qr_image = SL::Helper::QrBill->new(
+     \%biller_information,
+     \%biller_data,
+     \%payment_information,
+     \%invoice_recipient_data,
+     \%ref_nr_data,
+   );
+   $qr_image->generate($outfile);
+  } or do {
+   local $_ = $@; chomp; my $error = $_;
+   $::form->error($::locale->text('QR-Image generation failed: ' . $error));
+  };
+
+  $main::lxdebug->leave_sub();
+  return $outfile;
+}
+
 sub is_xvfb_running {
   $main::lxdebug->enter_sub();
 
index ca40971..920dee4 100644 (file)
@@ -3,6 +3,8 @@ package SL::Template::Plugin::KiviLatex;
 use strict;
 use parent qw( Template::Plugin::Filter );
 
+use SL::Template::LaTeX;
+
 my $cached_instance;
 
 sub new {
@@ -55,22 +57,7 @@ my %html_replace = (
 sub filter_html {
   my ($self, $text, $args) = @_;
 
-  $text =~ s{ \r+ }{}gx;
-  $text =~ s{ \n+ }{ }gx;
-  $text =~ s{ (?:\&nbsp;|\s)+ }{ }gx;
-  $text =~ s{ <ul>\s*</ul> | <ol>\s*</ol> }{}gx; # Remove lists without items. Can happen with copy & paste from e.g. LibreOffice.
-
-  my @parts = map {
-    if (substr($_, 0, 1) eq '<') {
-      s{ +}{}g;
-      $html_replace{$_} || '';
-
-    } else {
-      $::locale->quote_special_chars('Template/LaTeX', HTML::Entities::decode_entities($_));
-    }
-  } split(m{(<.*?>)}x, $text);
-
-  return join('', @parts);
+  return SL::Template::LaTeX->new->_format_html($text);
 }
 
 sub required_packages_for_html {
index 1beeb04..abb6046 100644 (file)
@@ -85,6 +85,8 @@ sub date_tag                 { return _call_presenter('date_tag',
 sub div_tag                  { return _call_presenter('div_tag',                  @_); }
 sub radio_button_tag         { return _call_presenter('radio_button_tag',         @_); }
 sub img_tag                  { return _call_presenter('img_tag',                  @_); }
+sub restricted_html          { return _call_presenter('restricted_html',          @_); }
+sub stripped_html            { return _call_presenter('stripped_html',            @_); }
 
 sub _set_id_attribute {
   my ($attributes, $name, $unique) = @_;
index f935a59..66424fc 100644 (file)
@@ -41,15 +41,6 @@ sub round_amount {
   return '';
 }
 
-sub format_amount_units {
-  my ($self, $amount, $amount_unit, $part_unit) = @_;
-
-  return $main::form->format_amount_units('amount'      => $amount,
-                                          'part_unit'   => $part_unit,
-                                          'amount_unit' => $amount_unit,
-                                          'conv_units'  => 'convertible_not_smaller');
-}
-
 sub format_percent {
   my ($self, $var, $places, $skip_zero) = @_;
 
index bd3e753..b6fa365 100644 (file)
@@ -9,13 +9,17 @@ use List::MoreUtils qw(any none);
 use SL::DBUtils;
 use SL::PrefixedNumber;
 use SL::DB;
+use SL::DB::DeliveryOrder::TypeData;
 
 use Rose::Object::MakeMethods::Generic
 (
  scalar => [ qw(type id number save dbh dbh_provided business_id) ],
 );
 
-my @SUPPORTED_TYPES = qw(invoice credit_note customer vendor sales_delivery_order purchase_delivery_order sales_order purchase_order sales_quotation request_quotation part service assembly assortment letter);
+my @SUPPORTED_TYPES = (
+  qw(invoice invoice_for_advance_payment final_invoice credit_note customer vendor sales_delivery_order purchase_delivery_order sales_order purchase_order sales_quotation request_quotation part service assembly assortment letter),
+  @{ SL::DB::DeliveryOrder::TypeData::valid_types() },
+);
 
 sub new {
   my $class = shift;
@@ -37,7 +41,7 @@ sub _get_filters {
   my $type    = $self->type;
   my %filters = ( where => '' );
 
-  if (any { $_ eq $type } qw(invoice credit_note)) {
+  if (any { $_ eq $type } qw(invoice invoice_for_advance_payment final_invoice credit_note)) {
     $filters{trans_number}  = "invnumber";
     $filters{numberfield}   = $type eq 'credit_note' ? "cnnumber" : "invnumber";
     $filters{table}         = "ar";
@@ -47,11 +51,12 @@ sub _get_filters {
     $filters{numberfield}   = "${type}number";
     $filters{table}         = $type;
 
-  } elsif ($type =~ /_delivery_order$/) {
-    $filters{trans_number}  = "donumber";
-    $filters{numberfield}   = $type eq 'sales_delivery_order' ? "sdonumber" : "pdonumber";
+  } elsif ($type =~ /_delivery_order$/ && SL::DB::DeliveryOrder::TypeData::is_valid_type($type)) {
+    $filters{trans_number}  = SL::DB::DeliveryOrder::TypeData::get3($type, 'properties', 'nr_key'),
+    $filters{numberfield}   = SL::DB::DeliveryOrder::TypeData::get3($type, 'properties', 'transnumber'),
     $filters{table}         = "delivery_orders";
-    $filters{where}         = $type =~ /^sales/ ? '(customer_id IS NOT NULL)' : '(vendor_id IS NOT NULL)';
+    $filters{where}         = "order_type = ?";
+    $filters{values}        = [ $::form->{type} ];
 
   } elsif ($type =~ /_order$/) {
     $filters{trans_number}  = "ordnumber";
@@ -96,6 +101,7 @@ sub is_unique {
   my @values = ($self->number);
 
   push @where, $filters{where} if $filters{where};
+  push @values, @{ $filters{values} } if $filters{values};
 
   if ($self->id) {
     push @where,  qq|id <> ?|;
@@ -131,7 +137,7 @@ sub create_unique {
 SQL
 
     do_query($form, $self->dbh, "LOCK TABLE " . $filters{table}) || die $self->dbh->errstr;
-    my %numbers_in_use = selectall_as_map($form, $self->dbh, $query, $filters{trans_number}, 'in_use');
+    my %numbers_in_use = selectall_as_map($form, $self->dbh, $query, $filters{trans_number}, 'in_use', @{ $filters{values} // [] });
 
     my $business_number;
     ($business_number) = selectfirst_array_query($form, $self->dbh, qq|SELECT customernumberinit FROM business WHERE id = ? FOR UPDATE|, $self->business_id) if $self->business_id;
index 69874ce..52e174f 100644 (file)
--- a/SL/WH.pm
+++ b/SL/WH.pm
@@ -61,7 +61,7 @@ sub transfer {
   require SL::DB::Part;
   require SL::DB::Employee;
 
-  my $employee   = SL::DB::Manager::Employee->find_by(login => $::myconfig{login});
+  my $employee   = SL::DB::Manager::Employee->current;
   my ($now)      = selectrow_query($::form, $::form->get_standard_dbh, qq|SELECT current_date|);
   my @directions = (undef, qw(out in transfer));
 
@@ -306,6 +306,18 @@ sub get_warehouse_journal {
 
   my $where_clause = @filter_ary ? join(" AND ", @filter_ary) . " AND " : '';
 
+  my ($cvar_where, @cvar_values) = CVar->build_filter_query(
+    module         => 'IC',
+    trans_id_field => 'p.id',
+    filter         => $form,
+    sub_module     => undef,
+  );
+
+  if ($cvar_where) {
+    $where_clause .= qq| ($cvar_where) AND |;
+    push @filter_vars, @cvar_values;
+  }
+
   $select_tokens{'trans'} = {
      "parts_id"             => "i1.parts_id",
      "qty"                  => "ABS(SUM(i1.qty))",
@@ -355,11 +367,11 @@ sub get_warehouse_journal {
   # take all the requested ones from the first hash and overwrite them from the out/in hashes if present.
   for my $i ('trans', 'out', 'in') {
     $select{$i} = join ', ', map { +/^l_/; ($select_tokens{$i}{"$'"} || $select_tokens{'trans'}{"$'"}) . " AS r_$'" }
-          ( grep( { !/qty$/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form), qw(l_parts_id l_qty l_partunit l_shippingdate) );
+          ( grep( { !/qty$/ and !/^l_cvar/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form), qw(l_parts_id l_qty l_partunit l_shippingdate) );
   }
 
   my $group_clause = join ", ", map { +/^l_/; "r_$'" }
-        ( grep( { !/qty$/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form), qw(l_parts_id l_partunit l_shippingdate l_itime) );
+        ( grep( { !/qty$/ and !/^l_cvar/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form), qw(l_parts_id l_partunit l_shippingdate l_itime) );
 
   $where_clause = defined($where_clause) ? $where_clause : '';
 
@@ -542,6 +554,11 @@ sub get_warehouse_report {
     push @filter_vars, $filter{partsid};
   }
 
+  if ($filter{partsgroup_id}) {
+    push @filter_ary,  "p.partsgroup_id = ?";
+    push @filter_vars, $filter{partsgroup_id};
+  }
+
   if ($filter{chargenumber}) {
     push @filter_ary,  "i.chargenumber ILIKE ?";
     push @filter_vars, like($filter{chargenumber});
@@ -627,11 +644,11 @@ sub get_warehouse_report {
   $form->{l_part_type}          = 'Y';
 
   my $select_clause = join ', ', map { +/^l_/; "$select_tokens{$'} AS $'" }
-        ( grep( { !/qty/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form),
+        ( grep( { !/qty/ and !/^l_cvar/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form),
           qw(l_parts_id l_qty l_partunit) );
 
   my $group_clause = join ", ", map { +/^l_/; "$'" }
-        ( grep( { !/qty/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form),
+        ( grep( { !/qty/ and !/^l_cvar/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form),
           qw(l_parts_id l_partunit) );
 
   my %join_tokens = (
@@ -639,9 +656,21 @@ sub get_warehouse_report {
     );
 
   my $joins = join ' ', grep { $_ } map { +/^l_/; $join_tokens{"$'"} }
-        ( grep( { !/qty/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form),
+        ( grep( { !/qty/ and !/^l_cvar/ and /^l_/ and $form->{$_} eq 'Y' } keys %$form),
           qw(l_parts_id l_qty l_partunit) );
 
+  my ($cvar_where, @cvar_values) = CVar->build_filter_query(
+    module         => 'IC',
+    trans_id_field => 'p.id',
+    filter         => $form,
+    sub_module     => undef,
+  );
+
+  if ($cvar_where) {
+    $where_clause .= qq| AND ($cvar_where)|;
+    push @filter_vars, @cvar_values;
+  }
+
   my $query =
     qq|SELECT * FROM ( SELECT $select_clause
       FROM inventory i
index 0b27d7d..85f6249 100644 (file)
@@ -17,24 +17,28 @@ use Rose::Object::MakeMethods::Generic (
 );
 
 my %type_to_path = (
-  sales_quotation         => 'angebote',
-  sales_order             => 'bestellungen',
-  request_quotation       => 'anfragen',
-  purchase_order          => 'lieferantenbestellungen',
-  sales_delivery_order    => 'verkaufslieferscheine',
-  purchase_delivery_order => 'einkaufslieferscheine',
-  credit_note             => 'gutschriften',
-  invoice                 => 'rechnungen',
-  purchase_invoice        => 'einkaufsrechnungen',
-  part                    => 'waren',
-  service                 => 'dienstleistungen',
-  assembly                => 'erzeugnisse',
-  letter                  => 'briefe',
-  general_ledger          => 'dialogbuchungen',
-  accounts_payable        => 'kreditorenbuchungen',
-  customer                => 'kunden',
-  vendor                  => 'lieferanten',
-  dunning                 => 'mahnungen',
+  sales_quotation             => 'angebote',
+  sales_order                 => 'bestellungen',
+  request_quotation           => 'anfragen',
+  purchase_order              => 'lieferantenbestellungen',
+  sales_delivery_order        => 'verkaufslieferscheine',
+  purchase_delivery_order     => 'einkaufslieferscheine',
+  supplier_delivery_order     => 'beistelllieferscheine',
+  rma_delivery_order          => 'retourenlieferscheine',
+  credit_note                 => 'gutschriften',
+  invoice                     => 'rechnungen',
+  invoice_for_advance_payment => 'rechnungen',
+  final_invoice               => 'rechnungen',
+  purchase_invoice            => 'einkaufsrechnungen',
+  part                        => 'waren',
+  service                     => 'dienstleistungen',
+  assembly                    => 'erzeugnisse',
+  letter                      => 'briefe',
+  general_ledger              => 'dialogbuchungen',
+  accounts_payable            => 'kreditorenbuchungen',
+  customer                    => 'kunden',
+  vendor                      => 'lieferanten',
+  dunning                     => 'mahnungen',
 );
 
 sub get_all_files {
index 313c9ff..54af37a 100644 (file)
@@ -58,6 +58,19 @@ sub store {
       $params{new_version} = 1;
     }
 
+    # Do not create a new version of the document if file size of last version is the same.
+    if ($params{new_version}) {
+      my $last_file_size = $last->size;
+      my $new_file_size;
+      if ($params{file}) {
+        croak 'No valid file' unless -f $params{file};
+        $new_file_size  = (stat($params{file}))[7];
+      } else {
+        $new_file_size  = length(${ $params{data} });
+      }
+      $params{new_version} = 0 if $last_file_size == $new_file_size;
+    }
+
     if ($params{new_version}) {
       my $new_version  = $self->webdav->version_scheme->next_version($last);
       my $sep          = $self->webdav->version_scheme->separator;
@@ -153,6 +166,9 @@ C<file> and C<data> are exclusive.
 If param C<new_version> is set, force a new version, even if the versioning
 scheme would keep the old one.
 
+No new version is stored if the file or data size is euqal to the size of
+the last stored version.
+
 =back
 
 =head1 SEE ALSO
index 8779d09..e4ece79 100644 (file)
@@ -42,6 +42,10 @@ sub full_filedescriptor {
   File::Spec->catfile($self->webdav->webdav_path, $self->filename);
 }
 
+sub size {
+  ($_[0]->stat)[7];
+}
+
 sub atime {
   DateTime->from_epoch(epoch => ($_[0]->stat)[8]);
 }
@@ -132,6 +136,10 @@ Returns the version string.
 
 Returns the extension.
 
+=item C<size>
+
+wrapped stat[7]
+
 =item C<atime>
 
 L<DateTime> wrapped stat[8]
diff --git a/SL/mebil/ERiC.pm b/SL/mebil/ERiC.pm
new file mode 100644 (file)
index 0000000..6ab6b84
--- /dev/null
@@ -0,0 +1,78 @@
+package SL::mebil::ERiC;
+
+#####################################################
+# Abhängigkeit: libinline-perl
+# diese Datei ist im falschen Zweig 
+#####################################################
+use File::Copy qw(copy);
+use strict;
+use Inline C => Config => BUILD_NOISY => 1, MYEXTLIB => '/home/mebil/workspace_cpp/mERiC/Debug/libmERiC.so';
+use Inline C => <<'C_END';
+
+int validate (char*, char*);
+int senddata (char*, char*, char*, char*);
+
+int c_validate(char* datenart, char* xml_file) {
+      int r = validate(datenart, xml_file);
+      return r;
+}
+int c_submit(char* datenart, char* xml_file, char* certificate_path, char* PIN) {
+      int r = senddata(datenart, xml_file, certificate_path, PIN);
+      return r;
+}
+
+C_END
+
+sub new {
+       # parameter: 1) type of data: xmlfile must be named: <datatype>.xml
+       #            2) xml file name
+       #            3) path to certificate
+       #            4) password
+       my $my_data = {
+               datatype         => $_[1],
+               xml_file         => $_[2],
+               certificate_path => $_[3],
+               PIN              => $_[4]};
+       bless $my_data;
+       return $my_data;
+}
+
+sub validate {
+       my $self = shift;
+       
+       # open xml file for reading
+       open (FILE, "$self->{xml_file}") or die "cannot open $self->{xml_file}";
+       
+       # check encoding
+       my $encod = <FILE>;
+       if ($encod =~ /UTF-8/) {
+               open (OUT, ">:encoding(iso-8859-1)", "data.xml");
+               print OUT "<?xml version=\"1.0\" encoding=\"ISO-8859-15\"?>\n";
+               my $line;
+               while ($line = <FILE>) {
+                       print OUT $line;
+               }
+               close (OUT);
+               close (FILE);
+               
+       }
+       elsif ($encod =~ /8859-15/) {
+               close (FILE);
+           copy "$self->{xml_file}", "data.xml";
+       }
+       else {
+               die "unknown encoding $encod";
+       }               
+
+       # call ERiC lib
+       return c_validate($self->{datatype}, "data.xml");
+}
+
+sub submit {
+       my $self = shift;
+
+       # call ERiC lib
+       return c_submit($self->{datatype}, "data.xml", $self->{certificate_path}, $self->{PIN});
+}
+
+1;
diff --git a/VERSION b/VERSION
index ee5ae26..8ab2db9 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1,2 @@
-3.5.8m1
+3.6.1
+
index 0b35fc7..541abab 100644 (file)
@@ -659,24 +659,25 @@ sub config {
   $form->{enabled_quick_searchmodules} = \@{$enabled_quick_search};
   $form->{default_quick_searchmodules} = \@quick_search_modules;
 
-  $form->{displayable_name_specs_by_module} = AM->displayable_name_specs_by_module();
-  $form->{positions_scrollbar_height}       = AM->positions_scrollbar_height();
-  $form->{purchase_search_makemodel}        = AM->purchase_search_makemodel();
-  $form->{sales_search_customer_partnumber} = AM->sales_search_customer_partnumber();
-  $form->{positions_show_update_button}     = AM->positions_show_update_button();
-  $form->{time_recording_use_duration}      = AM->time_recording_use_duration();
+  $form->{displayable_name_specs_by_module}       = AM->displayable_name_specs_by_module();
+  $form->{positions_scrollbar_height}             = AM->positions_scrollbar_height();
+  $form->{purchase_search_makemodel}              = AM->purchase_search_makemodel();
+  $form->{sales_search_customer_partnumber}       = AM->sales_search_customer_partnumber();
+  $form->{positions_show_update_button}           = AM->positions_show_update_button();
+  $form->{time_recording_use_duration}            = AM->time_recording_use_duration();
+  $form->{longdescription_dialog_size_percentage} = AM->longdescription_dialog_size_percentage();
 
   $myconfig{show_form_details} = 1 unless (defined($myconfig{show_form_details}));
   $form->{CAN_CHANGE_PASSWORD} = $main::auth->can_change_password();
   $form->{todo_cfg}            = { TODO->get_user_config('login' => $::myconfig{login}) };
-
-  $::request->{layout}->use_javascript("jquery.multiselect2side.js");
   $form->{title}               = $locale->text('Edit Preferences for #1', $::myconfig{login});
 
+  $::request->{layout}->use_javascript("${_}.js") for qw(jquery.multiselect2side ckeditor/ckeditor ckeditor/adapters/jquery);
+
   setup_am_config_action_bar();
   $form->header();
 
-  $form->{full_signature} = $form->create_email_signature();
+  $form->{company_signature} = SL::DB::Default->get->signature;
 
   print $form->parse_html_template('am/config');
 
@@ -1338,6 +1339,7 @@ sub save_warehouse {
   $main::auth->assert('config');
 
   $form->isblank("description", $locale->text('Description missing!'));
+  $form->isblank("number_of_new_bins", $locale->text('Number')  . $locale->text(' missing!'));
 
   $form->{number_of_new_bins} = $form->parse_amount(\%myconfig, $form->{number_of_new_bins});
 
index e7918d1..0e3048a 100644 (file)
@@ -136,12 +136,12 @@ sub load_record_template {
   $::form->{duedate}          = $today->to_kivitendo;
   $::form->{rowcount}         = @{ $template->items };
   $::form->{paidaccounts}     = 1;
-  $::form->{$_}               = $template->$_ for qw(department_id ordnumber taxincluded notes);
+  $::form->{$_}               = $template->$_ for qw(department_id ordnumber taxincluded notes transaction_description);
 
   if ($template->vendor) {
     $::form->{vendor_id} = $template->vendor_id;
     $::form->{vendor}    = $template->vendor->name;
-    $::form->{duedate}     = $template->vendor->payment->calc_date(reference_date => $today)->to_kivitendo if $template->vendor->payment;
+    $::form->{duedate}   = $template->vendor->payment->calc_date(reference_date => $today)->to_kivitendo if $template->vendor->payment;
   }
 
   my $row = 0;
@@ -206,21 +206,22 @@ sub save_record_template {
   } (1..($::form->{rowcount} || 1));
 
   $template->assign_attributes(
-    template_type  => 'ap_transaction',
-    template_name  => $new_name,
-
-    currency_id    => SL::DB::Manager::Currency->find_by(name => $::form->{currency})->id,
-    ar_ap_chart_id => $::form->{AP_chart_id}      || undef,
-    vendor_id      => $::form->{vendor_id}        || undef,
-    department_id  => $::form->{department_id}    || undef,
-    project_id     => $::form->{globalproject_id} || undef,
-    payment_id     => $::form->{payment_id}       || undef,
-    taxincluded    => $::form->{taxincluded}  ? 1 : 0,
-    direct_debit   => $::form->{direct_debit} ? 1 : 0,
-    ordnumber      => $::form->{ordnumber},
-    notes          => $::form->{notes},
-
-    items          => \@items,
+    template_type           => 'ap_transaction',
+    template_name           => $new_name,
+
+    currency_id             => SL::DB::Manager::Currency->find_by(name => $::form->{currency})->id,
+    ar_ap_chart_id          => $::form->{AP_chart_id}      || undef,
+    vendor_id               => $::form->{vendor_id}        || undef,
+    department_id           => $::form->{department_id}    || undef,
+    project_id              => $::form->{globalproject_id} || undef,
+    payment_id              => $::form->{payment_id}       || undef,
+    taxincluded             => $::form->{taxincluded}  ? 1 : 0,
+    direct_debit            => $::form->{direct_debit} ? 1 : 0,
+    ordnumber               => $::form->{ordnumber},
+    notes                   => $::form->{notes},
+    transaction_description => $::form->{transaction_description},
+
+    items                   => \@items,
   );
 
   eval {
@@ -493,6 +494,17 @@ sub form_header {
     $form->{"selected_taxchart_$i"}  = $selected_taxchart;
     $form->{"AP_amount_chart_id_$i"} = $amount_chart_id;
     $form->{"taxcharts_$i"}          = \@taxcharts;
+
+    # reverse charge hack for template, display two taxes
+    if ($taxchart_to_use->reverse_charge_chart_id) {
+      my $tmpnetamount;
+      ($tmpnetamount, $form->{"tax_reverse_$i"}) = $form->calculate_tax($form->parse_amount(\%myconfig, $form->{"amount_$i"}),
+                                                                        $taxchart_to_use->rate, $form->{taxincluded}, 2        );
+
+      $form->{"tax_charge_$i"}  = $form->{"tax_reverse_$i"} * -1;
+      $form->{"tax_reverse_$i"} = $form->format_amount(\%myconfig, $form->{"tax_reverse_$i"}, 2);
+      $form->{"tax_charge_$i"}  = $form->format_amount(\%myconfig, $form->{"tax_charge_$i"}, 2);
+    }
   }
 
   $form->{taxchart_value_title_sub} = sub {
@@ -798,9 +810,16 @@ sub post {
 
   my $zero_amount_posting = 1;
   for my $i (1 .. $form->{rowcount}) {
+
+    # no taxincluded for reverse charge
+    my ($used_tax_id) = split(/--/, $form->{"taxchart_$i"});
+    my $tax = SL::DB::Manager::Tax->find_by(id => $used_tax_id);
+    if ($tax->reverse_charge_chart_id && $form->{taxincluded}) {
+      $form->error($locale->text('Cannot Post AP transaction with tax included!'));
+    }
+
     if ($form->parse_amount(\%myconfig, $form->{"amount_$i"})) {
       $zero_amount_posting = 0;
-      last;
     }
   }
 
@@ -971,6 +990,8 @@ sub search {
   $form->{title} = $locale->text('Vendor Invoices & AP Transactions');
 
   $::form->{ALL_DEPARTMENTS} = SL::DB::Manager::Department->get_all_sorted;
+  $::form->{ALL_TAXZONES}    = SL::DB::Manager::TaxZone   ->get_all_sorted;
+
   # constants and subs for template
   $form->{vc_keys}   = sub { "$_[0]->{name}--$_[0]->{id}" };
 
@@ -1028,7 +1049,7 @@ sub ap_transactions {
 
   my @hidden_variables = map { "l_${_}" } @columns;
   push @hidden_variables, "l_subtotal", qw(open closed vendor invnumber ordnumber transaction_description notes project_id transdatefrom transdateto
-                                           parts_partnumber parts_description department_id);
+                                           parts_partnumber parts_description department_id taxzone_id);
 
   my $href = build_std_url('action=ap_transactions', grep { $form->{$_} } @hidden_variables);
 
@@ -1062,7 +1083,7 @@ sub ap_transactions {
     'insertdate'              => { 'text' => $locale->text('Insert Date'), },
   );
 
-  foreach my $name (qw(id transdate duedate invnumber ordnumber name datepaid employee shippingpoint shipvia transaction_description direct_debit department)) {
+  foreach my $name (qw(id transdate duedate invnumber ordnumber name datepaid employee shippingpoint shipvia transaction_description direct_debit department taxzone)) {
     my $sortdir                 = $form->{sort} eq $name ? 1 - $form->{sortdir} : $form->{sortdir};
     $column_defs{$name}->{link} = $href . "&sort=$name&sortdir=$sortdir";
   }
@@ -1225,20 +1246,21 @@ sub add_from_purchase_order {
   return if $order->type ne 'purchase_order';
 
   my $today                     = DateTime->today_local;
-  $::form->{title}              = "Add";
-  $::form->{vc}                 = 'vendor';
-  $::form->{vendor_id}          = $order->customervendor->id;
-  $::form->{vendor}             = $order->vendor->name;
-  $::form->{convert_from_oe_id} = $order->id;
-  $::form->{globalproject_id}   = $order->globalproject_id;
-  $::form->{ordnumber}          = $order->number;
-  $::form->{department_id}      = $order->department_id;
-  $::form->{currency}           = $order->currency->name;
-  $::form->{taxincluded}        = 1; # we use amount below, so tax is included
-  $::form->{transdate}          = $today->to_kivitendo;
-  $::form->{duedate}            = $today->to_kivitendo;
-  $::form->{duedate}            = $order->payment_terms->calc_date(reference_date => $today)->to_kivitendo if $order->payment_terms;
-  $::form->{deliverydate}       = $order->reqdate->to_kivitendo                                            if $order->reqdate;
+  $::form->{title}                   = "Add";
+  $::form->{vc}                      = 'vendor';
+  $::form->{vendor_id}               = $order->customervendor->id;
+  $::form->{vendor}                  = $order->vendor->name;
+  $::form->{convert_from_oe_id}      = $order->id;
+  $::form->{globalproject_id}        = $order->globalproject_id;
+  $::form->{ordnumber}               = $order->number;
+  $::form->{department_id}           = $order->department_id;
+  $::form->{transaction_description} = $order->transaction_description;
+  $::form->{currency}                = $order->currency->name;
+  $::form->{taxincluded}             = 1; # we use amount below, so tax is included
+  $::form->{transdate}               = $today->to_kivitendo;
+  $::form->{duedate}                 = $today->to_kivitendo;
+  $::form->{duedate}                 = $order->payment_terms->calc_date(reference_date => $today)->to_kivitendo if $order->payment_terms;
+  $::form->{deliverydate}            = $order->reqdate->to_kivitendo                                            if $order->reqdate;
   create_links();
 
   my $config_po_ap_workflow_chart_id = $::instance_conf->get_workflow_po_ap_chart_id;
@@ -1348,6 +1370,10 @@ sub setup_ap_display_form_action_bar {
 
     $is_linked_bank_transaction = 1;
   }
+  my $is_linked_gl_transaction;
+  if ($::form->{id} && SL::DB::Manager::ApGl->find_by(ap_id => $::form->{id})) {
+    $is_linked_gl_transaction = 1;
+  }
 
   my $create_post_action = sub {
     # $_[0]: description
@@ -1419,6 +1445,7 @@ sub setup_ap_display_form_action_bar {
                     : $is_storno           ? t8('Reversal invoices cannot be canceled.')
                     : $::form->{totalpaid} ? t8('Invoices with payments cannot be canceled.')
                     : $has_sepa_exports    ? t8('This invoice has been linked with a sepa export, undo this first.')
+                    : $is_linked_gl_transaction ? t8('This transaction is linked with a gl transaction. Please delete the ap transaction booking if needed.')
                     :                        undef,
         ],
         action => [ t8('Delete'),
@@ -1426,12 +1453,13 @@ sub setup_ap_display_form_action_bar {
           confirm  => t8('Do you really want to delete this object?'),
           disabled => !$may_edit_create           ? t8('You must not change this AP transaction.')
                     : !$::form->{id}              ? t8('This invoice has not been posted yet.')
-                    : $change_never               ? t8('Changing invoices has been disabled in the configuration.')
-                    : $change_on_same_day_only    ? t8('Invoices can only be changed on the day they are posted.')
-                    : $has_storno                 ? t8('This invoice has been canceled already.')
                     : $is_closed                  ? t8('The billing period has already been locked.')
                     : $has_sepa_exports           ? t8('This invoice has been linked with a sepa export, undo this first.')
                     : $is_linked_bank_transaction ? t8('This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.')
+                    : $is_linked_gl_transaction   ? undef # linked transactions can be deleted, if period is not closed
+                    : $change_never               ? t8('Changing invoices has been disabled in the configuration.')
+                    : $change_on_same_day_only    ? t8('Invoices can only be changed on the day they are posted.')
+                    : $has_storno                 ? t8('This invoice has been canceled already.')
                     :                               undef,
         ],
       ], # end of combobox "Storno"
index 71f94cc..cf0555f 100644 (file)
@@ -124,16 +124,17 @@ sub load_record_template {
 
   # Fill $::form from the template.
   my $today                   = DateTime->today_local;
-  $::form->{title}            = "Add";
-  $::form->{currency}         = $template->currency->name;
-  $::form->{direct_debit}     = $template->direct_debit;
-  $::form->{globalproject_id} = $template->project_id;
-  $::form->{AR_chart_id}      = $template->ar_ap_chart_id;
-  $::form->{transdate}        = $today->to_kivitendo;
-  $::form->{duedate}          = $today->to_kivitendo;
-  $::form->{rowcount}         = @{ $template->items };
-  $::form->{paidaccounts}     = 1;
-  $::form->{$_}               = $template->$_ for qw(department_id ordnumber taxincluded employee_id notes);
+  $::form->{title}                   = "Add";
+  $::form->{currency}                = $template->currency->name;
+  $::form->{direct_debit}            = $template->direct_debit;
+  $::form->{globalproject_id}        = $template->project_id;
+  $::form->{transaction_description} = $template->transaction_description;
+  $::form->{AR_chart_id}             = $template->ar_ap_chart_id;
+  $::form->{transdate}               = $today->to_kivitendo;
+  $::form->{duedate}                 = $today->to_kivitendo;
+  $::form->{rowcount}                = @{ $template->items };
+  $::form->{paidaccounts}            = 1;
+  $::form->{$_}                      = $template->$_ for qw(department_id ordnumber taxincluded employee_id notes);
 
   if ($template->customer) {
     $::form->{customer_id} = $template->customer_id;
@@ -197,21 +198,22 @@ sub save_record_template {
   } (1..($::form->{rowcount} || 1));
 
   $template->assign_attributes(
-    template_type  => 'ar_transaction',
-    template_name  => $new_name,
-
-    currency_id    => SL::DB::Manager::Currency->find_by(name => $::form->{currency})->id,
-    ar_ap_chart_id => $::form->{AR_chart_id}      || undef,
-    customer_id    => $::form->{customer_id}      || undef,
-    department_id  => $::form->{department_id}    || undef,
-    project_id     => $::form->{globalproject_id} || undef,
-    employee_id    => $::form->{employee_id}      || undef,
-    taxincluded    => $::form->{taxincluded}  ? 1 : 0,
-    direct_debit   => $::form->{direct_debit} ? 1 : 0,
-    ordnumber      => $::form->{ordnumber},
-    notes          => $::form->{notes},
-
-    items          => \@items,
+    template_type           => 'ar_transaction',
+    template_name           => $new_name,
+
+    currency_id             => SL::DB::Manager::Currency->find_by(name => $::form->{currency})->id,
+    ar_ap_chart_id          => $::form->{AR_chart_id}      || undef,
+    customer_id             => $::form->{customer_id}      || undef,
+    department_id           => $::form->{department_id}    || undef,
+    project_id              => $::form->{globalproject_id} || undef,
+    employee_id             => $::form->{employee_id}      || undef,
+    taxincluded             => $::form->{taxincluded}  ? 1 : 0,
+    direct_debit            => $::form->{direct_debit} ? 1 : 0,
+    ordnumber               => $::form->{ordnumber},
+    notes                   => $::form->{notes},
+    transaction_description => $::form->{transaction_description},
+
+    items                   => \@items,
   );
 
   eval {
@@ -959,9 +961,10 @@ sub search {
 
   $form->{title} = $locale->text('Invoices, Credit Notes & AR Transactions');
 
-  $form->{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all_sorted(query => [ deleted => 0 ]);
-  $form->{ALL_DEPARTMENTS} = SL::DB::Manager::Department->get_all_sorted;
-  $form->{ALL_BUSINESS_TYPES} = SL::DB::Manager::Business->get_all_sorted;
+  $form->{ALL_EMPLOYEES}      = SL::DB::Manager::Employee  ->get_all_sorted(query => [ deleted => 0 ]);
+  $form->{ALL_DEPARTMENTS}    = SL::DB::Manager::Department->get_all_sorted;
+  $form->{ALL_BUSINESS_TYPES} = SL::DB::Manager::Business  ->get_all_sorted;
+  $form->{ALL_TAXZONES}       = SL::DB::Manager::TaxZone   ->get_all_sorted;
 
   $form->{CT_CUSTOM_VARIABLES}                  = CVar->get_configs('module' => 'CT');
   ($form->{CT_CUSTOM_VARIABLES_FILTER_CODE},
@@ -1025,7 +1028,7 @@ sub ar_transactions {
     qw(ids transdate id type invnumber ordnumber cusordnumber donumber deliverydate name netamount tax amount paid
        datepaid due duedate transaction_description notes salesman employee shippingpoint shipvia
        marge_total marge_percent globalprojectnumber customernumber country ustid taxzone
-       payment_terms charts customertype direct_debit dunning_description department);
+       payment_terms charts customertype direct_debit dunning_description department attachments);
 
   my $ct_cvar_configs                 = CVar->get_configs('module' => 'CT');
   my @ct_includeable_custom_variables = grep { $_->{includeable} } @{ $ct_cvar_configs };
@@ -1036,7 +1039,8 @@ sub ar_transactions {
 
   my @hidden_variables = map { "l_${_}" } @columns;
   push @hidden_variables, "l_subtotal", qw(open closed customer invnumber ordnumber cusordnumber transaction_description notes project_id transdatefrom transdateto duedatefrom duedateto
-                                           employee_id salesman_id business_id parts_partnumber parts_description department_id show_marked_as_closed show_not_mailed);
+                                           employee_id salesman_id business_id parts_partnumber parts_description department_id show_marked_as_closed show_not_mailed
+                                           shippingpoint shipvia taxzone_id);
   push @hidden_variables, map { "cvar_$_->{name}" } @ct_searchable_custom_variables;
 
   $href =  $params{want_binary_pdf} ? '' : build_std_url('action=ar_transactions', grep { $form->{$_} } @hidden_variables);
@@ -1078,10 +1082,11 @@ sub ar_transactions {
     'direct_debit'            => { 'text' => $locale->text('direct debit'), },
     'department'              => { 'text' => $locale->text('Department'), },
     dunning_description       => { 'text' => $locale->text('Dunning level'), },
+    attachments               => { 'text' => $locale->text('Attachments'), },
     %column_defs_cvars,
   );
 
-  foreach my $name (qw(id transdate duedate invnumber ordnumber cusordnumber donumber deliverydate name datepaid employee shippingpoint shipvia transaction_description direct_debit department)) {
+  foreach my $name (qw(id transdate duedate invnumber ordnumber cusordnumber donumber deliverydate name datepaid employee shippingpoint shipvia transaction_description direct_debit department taxzone)) {
     my $sortdir                 = $form->{sort} eq $name ? 1 - $form->{sortdir} : $form->{sortdir};
     $column_defs{$name}->{link} = $href . "&sort=$name&sortdir=$sortdir";
   }
@@ -1159,6 +1164,13 @@ sub ar_transactions {
   if ($form->{closed}) {
     push @options, $locale->text('Closed');
   }
+  if ($form->{shipvia}) {
+    push @options, $locale->text('Ship via') . " : $form->{shipvia}";
+  }
+  if ($form->{shippingpoint}) {
+    push @options, $locale->text('Shipping Point') . " : $form->{shippingpoint}";
+  }
+
 
   $form->{ALL_PRINTERS} = SL::DB::Manager::Printer->get_all_sorted;
 
@@ -1195,15 +1207,30 @@ sub ar_transactions {
     $subtotals{marge_percent} = $subtotals{netamount} ? ($subtotals{marge_total} * 100 / $subtotals{netamount}) : 0;
     $totals{marge_percent}    = $totals{netamount}    ? ($totals{marge_total}    * 100 / $totals{netamount}   ) : 0;
 
+    # Preserve $ar->{type} before changing it to the abbreviation letter for
+    # getting files from file management below.
+    $ar->{object_type} = $ar->{type};
+
     my $is_storno  = $ar->{storno} &&  $ar->{storno_id};
     my $has_storno = $ar->{storno} && !$ar->{storno_id};
 
-    $ar->{type} =
-      $has_storno       ? $locale->text("Invoice with Storno (abbreviation)") :
-      $is_storno        ? $locale->text("Storno (one letter abbreviation)") :
-      $ar->{amount} < 0 ? $locale->text("Credit note (one letter abbreviation)") :
-      $ar->{invoice}    ? $locale->text("Invoice (one letter abbreviation)") :
-                          $locale->text("AR Transaction (abbreviation)");
+    if ($ar->{type} eq 'invoice_for_advance_payment') {
+      $ar->{type} =
+        $has_storno       ? $locale->text("Invoice for Advance Payment with Storno (abbreviation)") :
+        $is_storno        ? $locale->text("Storno (one letter abbreviation)") :
+                            $locale->text("Invoice for Advance Payment (one letter abbreviation)");
+
+    } elsif ($ar->{type} eq 'final_invoice') {
+      $ar->{type} = t8('Final Invoice (one letter abbreviation)');
+
+    } else {
+      $ar->{type} =
+        $has_storno       ? $locale->text("Invoice with Storno (abbreviation)") :
+        $is_storno        ? $locale->text("Storno (one letter abbreviation)") :
+        $ar->{amount} < 0 ? $locale->text("Credit note (one letter abbreviation)") :
+        $ar->{invoice}    ? $locale->text("Invoice (one letter abbreviation)") :
+                            $locale->text("AR Transaction (abbreviation)");
+    }
 
     map { $ar->{$_} = $form->format_amount(\%myconfig, $ar->{$_}, 2) } qw(netamount tax amount paid due marge_total marge_percent);
 
@@ -1227,6 +1254,20 @@ sub ar_transactions {
       align    => 'center',
     };
 
+    if ($::instance_conf->get_doc_storage && $form->{l_attachments}) {
+      my @files  = SL::File->get_all_versions(object_id   => $ar->{id},
+                                              object_type => $ar->{object_type} || 'invoice',
+                                              file_type   => 'attachment',);
+      if (scalar @files) {
+        my $html            = join '<br>', map { SL::Presenter::FileObject::file_object($_) } @files;
+        my $text            = join "\n",   map { $_->file_name                              } @files;
+        $row->{attachments} = { 'raw_data' => $html, data => $text };
+      } else {
+        $row->{attachments} = { };
+      }
+
+    }
+
     my $row_set = [ $row ];
 
     if (($form->{l_subtotal} eq 'Y')
index 33ef7e3..8cbdac7 100644 (file)
@@ -239,10 +239,10 @@ sub show_history {
 
   my $callback = build_std_url(qw(action longdescription trans_id_type input_name));
   my $restriction;
-  if ( $form->{trans_id_type} eq 'glid' ) {
-    $restriction = "AND ( snumbers LIKE 'invnumber%' OR what_done LIKE '%Buchungsnummer%' OR snumbers LIKE 'gltransaction%' OR snumbers LIKE 'emailjournal%' ) ";
-  } elsif ( $form->{trans_id_type} eq 'id' ) {
-    $restriction = " AND ( snumbers NOT LIKE 'invnumber_%' AND snumbers NOT LIKE 'gltransaction%' AND snumbers NOT LIKE 'emailjournal%' AND (what_done NOT LIKE '%Buchungsnummer%' OR what_done IS null))";
+  if ( $form->{trans_id_type} eq 'glid' ) { # for invoices
+    $restriction = "AND ( snumbers LIKE 'invnumber%' OR what_done LIKE '%Buchungsnummer%' OR snumbers LIKE 'gltransaction%' OR (snumbers LIKE 'emailjournal%' AND what_done ~ 'invoice|credit_note') ) ";
+  } elsif ( $form->{trans_id_type} eq 'id' ) { # for non invoices
+    $restriction = " AND ( snumbers NOT LIKE 'invnumber_%' AND snumbers NOT LIKE 'gltransaction%' AND (what_done NOT LIKE '%Buchungsnummer%' AND what_done NOT LIKE '%invoice%' OR what_done IS null))";
   } else {
     $restriction = '';
   };
index 86d1f5d..0a62ab5 100644 (file)
@@ -147,18 +147,19 @@ sub list_names {
   my @zugferd_settings_list = _zugferd_settings();
   my $zugferd_filter        = $form->{create_zugferd_invoices} eq '' ? undef : $zugferd_settings_list[$form->{create_zugferd_invoices} + 1]->[1];
 
-  push @options, $locale->text('Name') . " : $form->{name}"                                       if $form->{name};
-  push @options, $locale->text('Contact') . " : $form->{contact}"                                 if $form->{contact};
-  push @options, $locale->text('Number') . qq| : $form->{"$form->{db}number"}|                    if $form->{"$form->{db}number"};
-  push @options, $locale->text('E-mail') . " : $form->{email}"                                    if $form->{email};
-  push @options, $locale->text('Contact person (surname)')           . " : $form->{cp_name}"      if $form->{cp_name};
-  push @options, $locale->text('Billing/shipping address (city)')    . " : $form->{addr_city}"    if $form->{addr_city};
-  push @options, $locale->text('Billing/shipping address (zipcode)') . " : $form->{addr_zipcode}" if $form->{addr_zipcode};
-  push @options, $locale->text('Billing/shipping address (street)')  . " : $form->{addr_street}"  if $form->{addr_street};
-  push @options, $locale->text('Billing/shipping address (country)') . " : $form->{addr_country}" if $form->{addr_country};
-  push @options, $locale->text('Billing/shipping address (GLN)')     . " : $form->{addr_gln}"     if $form->{addr_gln};
-  push @options, $locale->text('Quick Search')                       . " : $form->{all}"          if $form->{all};
-  push @options, $locale->text('Factur-X/ZUGFeRD settings')          . " : $zugferd_filter"       if $zugferd_filter;
+  push @options, $locale->text('Name')                               . " : $form->{name}"                  if $form->{name};
+  push @options, $locale->text('Contact')                            . " : $form->{contact}"               if $form->{contact};
+  push @options, $locale->text('Number')                           . qq| : $form->{"$form->{db}number"}|   if $form->{"$form->{db}number"};
+  push @options, $locale->text('E-mail')                             . " : $form->{email}"                 if $form->{email};
+  push @options, $locale->text('All phone numbers')                  . " : $form->{all_phonenumbers}"      if $form->{all_phonenumbers};
+  push @options, $locale->text('Contact person (surname)')           . " : $form->{cp_name}"               if $form->{cp_name};
+  push @options, $locale->text('Billing/shipping address (city)')    . " : $form->{addr_city}"             if $form->{addr_city};
+  push @options, $locale->text('Billing/shipping address (zipcode)') . " : $form->{addr_zipcode}"          if $form->{addr_zipcode};
+  push @options, $locale->text('Billing/shipping address (street)')  . " : $form->{addr_street}"           if $form->{addr_street};
+  push @options, $locale->text('Billing/shipping address (country)') . " : $form->{addr_country}"          if $form->{addr_country};
+  push @options, $locale->text('Billing/shipping address (GLN)')     . " : $form->{addr_gln}"              if $form->{addr_gln};
+  push @options, $locale->text('Quick Search')                       . " : $form->{all}"                   if $form->{all};
+  push @options, $locale->text('Factur-X/ZUGFeRD settings')          . " : $zugferd_filter"                if $zugferd_filter;
 
   if ($form->{business_id}) {
     my $business = SL::DB::Manager::Business->find_by(id => $form->{business_id});
@@ -237,6 +238,7 @@ sub list_names {
   my @hidden_variables  = ( qw(
       db status obsolete name contact email cp_name addr_street addr_zipcode
       addr_city addr_country addr_gln business_id salesman_id insertdateto insertdatefrom all
+      all_phonenumbers
     ), "$form->{db}number",
     map({ "cvar_$_->{name}" } @searchable_custom_variables),
     map({'cvar_'. $_->{name} .'_from'} grep({$_->{type} eq 'date'} @searchable_custom_variables)),
index c4640ef..419b4f4 100644 (file)
@@ -317,7 +317,10 @@ sub set_email {
   $main::auth->assert('dunning_edit');
 
   $form->{"title"} = $locale->text("Set eMail text");
-  $form->header(no_layout => 1);
+  $form->header(
+    no_layout       => 1,
+    use_javascripts => [ qw(ckeditor/ckeditor ckeditor/adapters/jquery) ],
+  );
   print($form->parse_html_template("dunning/set_email"));
 
   $main::lxdebug->leave_sub();
index 6adf190..e0b4dbc 100644 (file)
@@ -36,7 +36,10 @@ use List::MoreUtils qw(uniq);
 use List::Util qw(max sum);
 use POSIX qw(strftime);
 
+use SL::Controller::DeliveryOrder;
 use SL::DB::DeliveryOrder;
+use SL::DB::DeliveryOrder::TypeData qw(:types validate_type);
+use SL::Helper::UserPreferences::DisplayPreferences;
 use SL::DO;
 use SL::IR;
 use SL::IS;
@@ -55,8 +58,18 @@ use strict;
 
 # end of main
 
+sub check_do_access_for_edit {
+  validate_type($::form->{type});
+
+  my $right = SL::DB::DeliveryOrder::TypeData::get3($::form->{type}, "rights", "edit");
+  $main::auth->assert($right);
+}
+
 sub check_do_access {
-  $main::auth->assert($main::form->{type} . '_edit');
+  validate_type($::form->{type});
+
+  my $right = SL::DB::DeliveryOrder::TypeData::get3($::form->{type}, "rights", "view");
+  $main::auth->assert($right);
 }
 
 sub set_headings {
@@ -85,7 +98,7 @@ sub set_headings {
 sub add {
   $main::lxdebug->enter_sub();
 
-  check_do_access();
+  check_do_access_for_edit();
 
   if (($::form->{type} =~ /purchase/) && !$::instance_conf->get_allow_new_purchase_invoice) {
     $::form->show_generic_error($::locale->text("You do not have the permissions to access this function."));
@@ -98,7 +111,7 @@ sub add {
   $form->{show_details} = $::myconfig{show_form_details};
   $form->{callback} = build_std_url('action=add', 'type', 'vc') unless ($form->{callback});
 
-  order_links();
+  order_links(is_new => 1);
   prepare_order();
   display_form();
 
@@ -168,6 +181,7 @@ sub order_links {
 
   check_do_access();
 
+  my %params   = @_;
   my $form     = $main::form;
   my %myconfig = %main::myconfig;
 
@@ -186,6 +200,7 @@ sub order_links {
   } else {
     IS->get_customer(\%myconfig, \%$form);
     $form->{discount} = $form->{customer_discount};
+    $form->{billing_address_id} = $form->{default_billing_address_id} if $params{is_new};
   }
 
   $form->restore_vars(qw(payment_id language_id taxzone_id intnotes cp_id delivery_term_id));
@@ -247,11 +262,15 @@ sub setup_do_action_bar {
   if (ref $undo_date eq 'DateTime' && ref $insertdate eq 'DateTime') {
     $undo_transfer = $insertdate > $undo_date;
   }
+
+  my $may_edit_create = $::auth->assert(SL::DB::DeliveryOrder::TypeData::get3($::form->{type}, "rights", "edit"), 1);
+
   for my $bar ($::request->layout->get('actionbar')) {
     $bar->add(
       action =>
         [ t8('Update'),
           submit    => [ '#form', { action => "update" } ],
+          disabled  => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
           id        => 'update_button',
           accesskey => 'enter',
         ],
@@ -261,20 +280,24 @@ sub setup_do_action_bar {
           t8('Save'),
           submit   => [ '#form', { action => "save" } ],
           checks   => [ 'kivi.validate_form' ],
-          disabled => $::form->{delivered} ? t8('This record has already been delivered.') : undef,
+          disabled => !$may_edit_create    ? t8('You do not have the permissions to access this function.')
+                    : $::form->{delivered} ? t8('This record has already been delivered.')
+                    :                        undef,
         ],
         action => [
           t8('Save as new'),
           submit   => [ '#form', { action => "save_as_new" } ],
           checks   => [ 'kivi.validate_form' ],
-          disabled => !$::form->{id},
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.')
+                    : !$::form->{id},
         ],
         action => [
           t8('Mark as closed'),
           submit   => [ '#form', { action => "mark_closed" } ],
           checks   => [ 'kivi.validate_form' ],
           confirm  => t8('This will remove the delivery order from showing as open even if contents are not delivered. Proceed?'),
-          disabled => !$::form->{id}    ? t8('This record has not been saved yet.')
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.')
+                    : !$::form->{id}    ? t8('This record has not been saved yet.')
                     : $::form->{closed} ? t8('This record has already been closed.')
                     :                     undef,
         ],
@@ -284,7 +307,8 @@ sub setup_do_action_bar {
         t8('Delete'),
         submit   => [ '#form', { action => "delete" } ],
         confirm  => t8('Do you really want to delete this object?'),
-        disabled => !$::form->{id}                                                                              ? t8('This record has not been saved yet.')
+        disabled => !$may_edit_create                                                                           ? t8('You do not have the permissions to access this function.')
+                  : !$::form->{id}                                                                              ? t8('This record has not been saved yet.')
                   : $::form->{delivered}                                                                        ? t8('This record has already been delivered.')
                   : ($::form->{vc} eq 'customer' && !$::instance_conf->get_sales_delivery_order_show_delete)    ? t8('Deleting this type of record has been disabled in the configuration.')
                   : ($::form->{vc} eq 'vendor'   && !$::instance_conf->get_purchase_delivery_order_show_delete) ? t8('Deleting this type of record has been disabled in the configuration.')
@@ -296,28 +320,36 @@ sub setup_do_action_bar {
           t8('Transfer out'),
           submit   => [ '#form', { action => "transfer_out" } ],
           checks   => [ 'kivi.validate_form', @transfer_qty ],
-          disabled => $::form->{delivered} ? t8('This record has already been delivered.') : undef,
+          disabled => !$may_edit_create    ? t8('You do not have the permissions to access this function.')
+                    : $::form->{delivered} ? t8('This record has already been delivered.')
+                    :                        undef,
           only_if  => $is_customer,
         ],
         action => [
           t8('Transfer out via default'),
           submit   => [ '#form', { action => "transfer_out_default" } ],
           checks   => [ 'kivi.validate_form' ],
-          disabled => $::form->{delivered} ? t8('This record has already been delivered.') : undef,
+          disabled => !$may_edit_create    ? t8('You do not have the permissions to access this function.')
+                    : $::form->{delivered} ? t8('This record has already been delivered.')
+                    :                        undef,
           only_if  => $is_customer && $::instance_conf->get_transfer_default,
         ],
         action => [
           t8('Transfer in'),
           submit   => [ '#form', { action => "transfer_in" } ],
           checks   => [ 'kivi.validate_form', @transfer_qty ],
-          disabled => $::form->{delivered} ? t8('This record has already been delivered.') : undef,
+          disabled => !$may_edit_create    ? t8('You do not have the permissions to access this function.')
+                    : $::form->{delivered} ? t8('This record has already been delivered.')
+                    :                        undef,
           only_if  => !$is_customer,
         ],
         action => [
           t8('Transfer in via default'),
           submit   => [ '#form', { action => "transfer_in_default" } ],
           checks   => [ 'kivi.validate_form' ],
-          disabled => $::form->{delivered} ? t8('This record has already been delivered.') : undef,
+          disabled => !$may_edit_create    ? t8('You do not have the permissions to access this function.')
+                    : $::form->{delivered} ? t8('This record has already been delivered.')
+                    :                        undef,
           only_if  => !$is_customer && $::instance_conf->get_transfer_default,
         ],
         action => [
@@ -325,7 +357,9 @@ sub setup_do_action_bar {
           submit   => [ '#form', { action => "delete_transfers" } ],
           checks   => [ 'kivi.validate_form' ],
           only_if  => $::form->{delivered},
-          disabled => !$undo_transfer ? t8('Transfer date exceeds the maximum allowed interval.') : undef,
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.')
+                    : !$undo_transfer   ? t8('Transfer date exceeds the maximum allowed interval.')
+                    :                     undef,
         ],
       ], # end of combobox "Transfer out"
 
@@ -346,14 +380,17 @@ sub setup_do_action_bar {
         action => [ t8('Export') ],
         action => [
           t8('Print'),
-          call   => [ 'kivi.SalesPurchase.show_print_dialog' ],
-          checks => [ 'kivi.validate_form' ],
+          call     => [ 'kivi.SalesPurchase.show_print_dialog' ],
+          checks   => [ 'kivi.validate_form' ],
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
         ],
         action => [
           t8('E Mail'),
           call   => [ 'kivi.SalesPurchase.show_email_dialog' ],
           checks => [ 'kivi.validate_form' ],
-          disabled => !$::form->{id} ? t8('This record has not been saved yet.') : undef,
+          disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.')
+                    : !$::form->{id} ?    t8('This record has not been saved yet.')
+                    :                     undef,
         ],
       ], # end of combobox "Export"
 
@@ -481,6 +518,7 @@ sub form_header {
 
 
   $form->{follow_up_trans_info} = $form->{donumber} .'('. $form->{VC_OBJ}->name .')' if $form->{VC_OBJ};
+  $form->{longdescription_dialog_size_percentage} = SL::Helper::UserPreferences::DisplayPreferences->new()->get_longdescription_dialog_size_percentage();
 
   $::request->{layout}->use_javascript(map { "${_}.js" } qw(kivi.File kivi.MassDeliveryOrderPrint kivi.SalesPurchase kivi.Part kivi.CustomerVendor kivi.Validator ckeditor/ckeditor ckeditor/adapters/jquery kivi.io));
 
@@ -548,8 +586,12 @@ sub update_delivery_order {
   if (($form->{"previous_${vc}_id"} || $form->{"${vc}_id"}) != $form->{"${vc}_id"}) {
     $::form->{salesman_id} = SL::DB::Manager::Employee->current->id if exists $::form->{salesman_id};
 
-    IS->get_customer(\%myconfig, $form) if $vc eq 'customer';
-    IR->get_vendor(\%myconfig, $form)   if $vc eq 'vendor';
+    if ($vc eq 'customer') {
+      IS->get_customer(\%myconfig, $form);
+      $::form->{billing_address_id} = $::form->{default_billing_address_id};
+    } else {
+      IR->get_vendor(\%myconfig, $form);
+    }
   }
 
   $form->{discount} =  $form->{"$form->{vc}_discount"} if defined $form->{"$form->{vc}_discount"};
@@ -881,7 +923,9 @@ sub orders {
       'align'    => 'center',
     };
 
-    $row->{donumber}->{link}  = $edit_url       . "&id=" . E($dord->{id})      . "&callback=${callback}";
+    $row->{donumber}->{link}  = SL::DB::DeliveryOrder::TypeData::get3($dord->{order_type}, "show_menu", "new_controller")
+                              ? SL::Controller::DeliveryOrder->url_for(action => "edit", id => $dord->{id}, type => $dord->{order_type})
+                              : $edit_url  . "&id=" . E($dord->{id})      . "&callback=${callback}";
     $row->{ordnumber}->{link} = $edit_order_url . "&id=" . E($dord->{oe_id})   . "&callback=${callback}" if $dord->{oe_id};
     $report->add_data($row);
 
@@ -900,7 +944,7 @@ sub save {
 
   my (%params) = @_;
 
-  check_do_access();
+  check_do_access_for_edit();
 
   my $form     = $main::form;
   my %myconfig = %main::myconfig;
@@ -935,8 +979,12 @@ sub save {
   if (($form->{"previous_${vc}_id"} || $form->{"${vc}_id"}) != $form->{"${vc}_id"}) {
     $::form->{salesman_id} = SL::DB::Manager::Employee->current->id if exists $::form->{salesman_id};
 
-    IS->get_customer(\%myconfig, $form) if $vc eq 'customer';
-    IR->get_vendor(\%myconfig, $form)   if $vc eq 'vendor';
+    if ($vc eq 'customer') {
+      IS->get_customer(\%myconfig, $form);
+      $::form->{billing_address_id} = $::form->{default_billing_address_id};
+    } else {
+      IR->get_vendor(\%myconfig, $form);
+    }
 
     update();
     $::dispatcher->end_request;
@@ -978,7 +1026,7 @@ sub save {
 sub delete {
   $main::lxdebug->enter_sub();
 
-  check_do_access();
+  check_do_access_for_edit();
 
   my $form     = $main::form;
   my %myconfig = %main::myconfig;
@@ -1004,7 +1052,7 @@ sub delete {
 sub delete_transfers {
   $main::lxdebug->enter_sub();
 
-  check_do_access();
+  check_do_access_for_edit();
 
   my $form     = $main::form;
   my %myconfig = %main::myconfig;
@@ -1045,6 +1093,8 @@ sub invoice {
 
   $main::auth->assert($form->{type} eq 'purchase_delivery_order' ? 'vendor_invoice_edit' : 'invoice_edit');
 
+  $form->get_employee();
+
   $form->{convert_from_do_ids} = $form->{id};
   # if we have a reqdate (Liefertermin), this is definetely the preferred
   # deliverydate for invoices
@@ -1256,7 +1306,7 @@ sub invoice_multi {
 sub save_as_new {
   $main::lxdebug->enter_sub();
 
-  check_do_access();
+  check_do_access_for_edit();
 
   my $form     = $main::form;
 
@@ -1300,11 +1350,9 @@ sub calculate_stock_in_out {
   my $sum      = AM->sum_with_unit(map { $_->{qty}, $_->{unit} } @{ $sinfo });
   my $matches  = $do_qty == $sum;
 
-  my $content  = $form->format_amount_units('amount'      => $sum * 1,
-                                            'part_unit'   => $form->{"partunit_$i"},
-                                            'amount_unit' => $all_units->{$form->{"partunit_$i"}}->{base_unit},
-                                            'conv_units'  => 'convertible_not_smaller',
-                                            'max_places'  => 2);
+  my $amount_unit = $all_units->{$form->{"partunit_$i"}}->{base_unit};
+  my $content     = $form->format_amount(\%::myconfig, AM->convert_unit($amount_unit, $form->{"unit_$i"}) * $sum * 1) . ' ' . $form->{"unit_$i"};
+
   $content     = qq|<span id="stock_in_out_qty_display_${i}">${content}</span><input type=hidden id='stock_in_out_qty_matches_$i' value='$matches'> <input type="button" onclick="open_stock_in_out_window('${in_out}', $i);" value="?">|;
 
   $main::lxdebug->leave_sub();
@@ -1438,11 +1486,8 @@ sub _stock_in_out_set_qty_display {
   my $form             = $::form;
   my $all_units        = AM->retrieve_all_units();
   my $sum              = AM->sum_with_unit(map { $_->{qty}, $_->{unit} } @{ $stock_info });
-  $form->{qty_display} = $form->format_amount_units(amount      => $sum * 1,
-                                                    part_unit   => $form->{partunit},
-                                                    amount_unit => $all_units->{ $form->{partunit} }->{base_unit},
-                                                    conv_units  => 'convertible_not_smaller',
-                                                    max_places  => 2);
+  my $amount_unit      = $all_units->{$form->{"partunit"}}->{base_unit};
+  $form->{qty_display} = $form->format_amount(\%::myconfig, AM->convert_unit($amount_unit, $form->{"do_unit"}) * $sum * 1) . ' ' . $form->{"do_unit"};
 }
 
 sub set_stock_in {
@@ -1496,10 +1541,7 @@ sub stock_out_form {
 
   if (!$form->{delivered}) {
     foreach my $row (@contents) {
-      $row->{available_qty} = $form->format_amount_units('amount'      => $row->{qty} * 1,
-                                                         'part_unit'   => $part_info->{unit},
-                                                         'conv_units'  => 'convertible_not_smaller',
-                                                         'max_places'  => 2);
+      $row->{available_qty} = $form->format_amount(\%::myconfig, $row->{qty} * 1) . ' ' . $part_info->{unit};
 
       foreach my $sinfo (@{ $stock_info }) {
         next if (($row->{bin_id}       != $sinfo->{bin_id}) ||
@@ -1730,18 +1772,14 @@ sub transfer_out {
                                                      $binfo->{bin_description},
                                                      $request->{chargenumber} ? $locale->text('chargenumber #1', $request->{chargenumber}) : $locale->text('no chargenumber'),
                                                      $request->{bestbefore} ? $locale->text('bestbefore #1', $request->{bestbefore}) : $locale->text('no bestbefore'),
-                                                     $form->format_amount_units('amount'      => $request->{sum_base_qty},
-                                                                                'part_unit'   => $pinfo->{unit},
-                                                                                'conv_units'  => 'convertible_not_smaller'));
+                                                     $form->format_amount(\%::myconfig, $request->{sum_base_qty}) . ' ' . $pinfo->{unit});
         } else {
             push @{ $form->{ERRORS} }, $locale->text("There is not enough available of '#1' at warehouse '#2', bin '#3', #4, for the transfer of #5.",
                                                      $pinfo->{description},
                                                      $binfo->{warehouse_description},
                                                      $binfo->{bin_description},
                                                      $request->{chargenumber} ? $locale->text('chargenumber #1', $request->{chargenumber}) : $locale->text('no chargenumber'),
-                                                     $form->format_amount_units('amount'      => $request->{sum_base_qty},
-                                                                                'part_unit'   => $pinfo->{unit},
-                                                                                'conv_units'  => 'convertible_not_smaller'));
+                                                     $form->format_amount(\%::myconfig, $request->{sum_base_qty}) . ' ' . $pinfo->{unit});
         }
       }
     }
@@ -1785,7 +1823,7 @@ sub mark_closed {
 sub display_form {
   $::lxdebug->enter_sub;
 
-  $::auth->assert('purchase_delivery_order_edit | sales_delivery_order_edit');
+  check_do_access();
 
   relink_accounts();
   retrieve_partunits();
index d9001e3..b987d1f 100644 (file)
@@ -100,7 +100,10 @@ sub display_form {
   my %params;
   $params{not_id}     = $form->{id} if ($form->{id});
   $params{trans_id}   = $form->{LINKS}->[0]->{trans_id} if (@{ $form->{LINKS} });
-  $form->{FOLLOW_UPS} = FU->follow_ups(%params);
+
+  $form->{sort}               = 'follow_up_date';
+  $form->{FOLLOW_UPS_DONE}    = FU->follow_ups(%params,     done => 1);
+  $form->{FOLLOW_UPS_PENDING} = FU->follow_ups(%params, not_done => 1);
 
   setup_fu_display_form_action_bar() unless $::form->{POPUP_MODE};
 
index 4e6d263..de7d924 100644 (file)
@@ -178,6 +178,7 @@ sub edit_email_strings {
   setup_generictranslations_edit_email_strings_action_bar();
 
   $form->{title} = $locale->text('Edit preset email strings');
+  $::request->{layout}->use_javascript(map { "${_}.js" } qw(ckeditor/ckeditor ckeditor/adapters/jquery));
   $form->header();
   print $form->parse_html_template('generictranslations/edit_email_strings',{ 'MAIL_STRINGS' => \%mail_strings });
 
index a664f6f..faca8ce 100644 (file)
@@ -38,7 +38,9 @@ use strict;
 use POSIX qw(strftime);
 use List::Util qw(first sum);
 
+use SL::DB::ApGl;
 use SL::DB::RecordTemplate;
+use SL::DB::ReconciliationLink;
 use SL::DB::BankTransactionAccTrans;
 use SL::DB::Tax;
 use SL::FU;
@@ -112,7 +114,7 @@ sub load_record_template {
   $::form->{duedate}          = $today->to_kivitendo;
   $::form->{rowcount}         = @{ $template->items };
   $::form->{paidaccounts}     = 1;
-  $::form->{$_}               = $template->$_     for qw(department_id taxincluded ob_transaction cb_transaction reference description show_details);
+  $::form->{$_}               = $template->$_     for qw(department_id taxincluded ob_transaction cb_transaction reference description show_details transaction_description);
   $::form->{$_}               = $dummy_form->{$_} for qw(closedto revtrans previous_id previous_gldate);
 
   my $row = 0;
@@ -184,15 +186,16 @@ sub save_record_template {
     template_type  => 'gl_transaction',
     template_name  => $new_name,
 
-    currency_id    => $::instance_conf->get_currency_id,
-    department_id  => $::form->{department_id}    || undef,
-    project_id     => $::form->{globalproject_id} || undef,
-    taxincluded    => $::form->{taxincluded}     ? 1 : 0,
-    ob_transaction => $::form->{ob_transaction}  ? 1 : 0,
-    cb_transaction => $::form->{cb_transaction}  ? 1 : 0,
-    reference      => $::form->{reference},
-    description    => $::form->{description},
-    show_details   => $::form->{show_details},
+    currency_id             => $::instance_conf->get_currency_id,
+    department_id           => $::form->{department_id}    || undef,
+    project_id              => $::form->{globalproject_id} || undef,
+    taxincluded             => $::form->{taxincluded}     ? 1 : 0,
+    ob_transaction          => $::form->{ob_transaction}  ? 1 : 0,
+    cb_transaction          => $::form->{cb_transaction}  ? 1 : 0,
+    reference               => $::form->{reference},
+    description             => $::form->{description},
+    show_details            => $::form->{show_details},
+    transaction_description => $::form->{transaction_description},
 
     items          => \@items,
   );
@@ -425,26 +428,28 @@ sub generate_report {
   my $ml = ($form->{ml} =~ /(A|E|Q)/) ? -1 : 1;
 
   my @columns = qw(
-    transdate      gldate   id      reference      description
-    notes          source   doccnt  debit          debit_accno
-    credit         credit_accno     debit_tax      debit_tax_accno
-    credit_tax     credit_tax_accno balance        projectnumbers
-    department     employee
+    transdate     gldate              id                         reference
+    description   notes               transaction_description    source
+    doccnt        debit               debit_accno
+    credit        credit_accno        debit_tax                  debit_tax_accno
+    credit_tax    credit_tax_accno    balance                    projectnumbers
+    department    employee
   );
 
   # add employee here, so that variable is still known and passed in url when choosing a different sort order in resulting table
-  my @hidden_variables = qw(accno source reference description notes project_id datefrom dateto employee_id datesort category l_subtotal department_id);
+  my @hidden_variables = qw(accno source reference description notes project_id datefrom dateto employee_id datesort category l_subtotal department_id transaction_description);
   push @hidden_variables, map { "l_${_}" } @columns;
 
   my $employee = $form->{employee_id} ? SL::DB::Employee->new(id => $form->{employee_id})->load->name : '';
 
   my (@options, @date_options);
-  push @options,      $locale->text('Account')     . " : $form->{accno} $form->{account_description}" if ($form->{accno});
-  push @options,      $locale->text('Source')      . " : $form->{source}"                             if ($form->{source});
-  push @options,      $locale->text('Reference')   . " : $form->{reference}"                          if ($form->{reference});
-  push @options,      $locale->text('Description') . " : $form->{description}"                        if ($form->{description});
-  push @options,      $locale->text('Notes')       . " : $form->{notes}"                              if ($form->{notes});
-  push @options,      $locale->text('Employee')    . " : $employee"                                   if $employee;
+  push @options,      $locale->text('Account')                 . " : $form->{accno} $form->{account_description}" if ($form->{accno});
+  push @options,      $locale->text('Source')                  . " : $form->{source}"                             if ($form->{source});
+  push @options,      $locale->text('Reference')               . " : $form->{reference}"                          if ($form->{reference});
+  push @options,      $locale->text('Description')             . " : $form->{description}"                        if ($form->{description});
+  push @options,      $locale->text('Notes')                   . " : $form->{notes}"                              if ($form->{notes});
+  push @options,      $locale->text('Transaction description') . " : $form->{transaction_description}"            if $form->{transaction_description};
+  push @options,      $locale->text('Employee')                . " : $employee"                                   if $employee;
   my $datesorttext = $form->{datesort} eq 'transdate' ? $locale->text('Transdate') :  $locale->text('Gldate');
   push @date_options,      "$datesorttext"                              if ($form->{datesort} and ($form->{datefrom} or $form->{dateto}));
   push @date_options, $locale->text('From'), $locale->date(\%myconfig, $form->{datefrom}, 1)          if ($form->{datefrom});
@@ -470,29 +475,30 @@ sub generate_report {
   $form->{l_doccnt}           = $form->{l_source} ? 'Y' : '';
 
   my %column_defs = (
-    'id'               => { 'text' => $locale->text('ID'), },
-    'transdate'        => { 'text' => $locale->text('Transdate'), },
-    'gldate'           => { 'text' => $locale->text('Gldate'), },
-    'reference'        => { 'text' => $locale->text('Reference'), },
-    'source'           => { 'text' => $locale->text('Source'), },
-    'doccnt'           => { 'text' => $locale->text('Document Count'), },
-    'description'      => { 'text' => $locale->text('Description'), },
-    'notes'            => { 'text' => $locale->text('Notes'), },
-    'debit'            => { 'text' => $locale->text('Debit'), },
-    'debit_accno'      => { 'text' => $locale->text('Debit Account'), },
-    'credit'           => { 'text' => $locale->text('Credit'), },
-    'credit_accno'     => { 'text' => $locale->text('Credit Account'), },
-    'debit_tax'        => { 'text' => $locale->text('Debit Tax'), },
-    'debit_tax_accno'  => { 'text' => $locale->text('Debit Tax Account'), },
-    'credit_tax'       => { 'text' => $locale->text('Credit Tax'), },
-    'credit_tax_accno' => { 'text' => $locale->text('Credit Tax Account'), },
-    'balance'          => { 'text' => $locale->text('Balance'), },
-    'projectnumbers'   => { 'text' => $locale->text('Project Numbers'), },
-    'department'       => { 'text' => $locale->text('Department'), },
-    'employee'         => { 'text' => $locale->text('Employee'), },
+    'id'                      => { 'text' => $locale->text('ID'), },
+    'transdate'               => { 'text' => $locale->text('Transdate'), },
+    'gldate'                  => { 'text' => $locale->text('Gldate'), },
+    'reference'               => { 'text' => $locale->text('Reference'), },
+    'source'                  => { 'text' => $locale->text('Source'), },
+    'doccnt'                  => { 'text' => $locale->text('Document Count'), },
+    'description'             => { 'text' => $locale->text('Description'), },
+    'notes'                   => { 'text' => $locale->text('Notes'), },
+    'debit'                   => { 'text' => $locale->text('Debit'), },
+    'debit_accno'             => { 'text' => $locale->text('Debit Account'), },
+    'credit'                  => { 'text' => $locale->text('Credit'), },
+    'credit_accno'            => { 'text' => $locale->text('Credit Account'), },
+    'debit_tax'               => { 'text' => $locale->text('Debit Tax'), },
+    'debit_tax_accno'         => { 'text' => $locale->text('Debit Tax Account'), },
+    'credit_tax'              => { 'text' => $locale->text('Credit Tax'), },
+    'credit_tax_accno'        => { 'text' => $locale->text('Credit Tax Account'), },
+    'balance'                 => { 'text' => $locale->text('Balance'), },
+    'projectnumbers'          => { 'text' => $locale->text('Project Numbers'), },
+    'department'              => { 'text' => $locale->text('Department'), },
+    'employee'                => { 'text' => $locale->text('Employee'), },
+    'transaction_description' => { 'text' => $locale->text('Transaction description'), },
   );
 
-  foreach my $name (qw(id transdate gldate reference description debit_accno credit_accno debit_tax_accno credit_tax_accno department)) {
+  foreach my $name (qw(id transdate gldate reference description debit_accno credit_accno debit_tax_accno credit_tax_accno department transaction_description)) {
     my $sortname                = $name =~ m/accno/ ? 'accno' : $name;
     my $sortdir                 = $sortname eq $form->{sort} ? 1 - $form->{sortdir} : $form->{sortdir};
     $column_defs{$name}->{link} = $callback . "&sort=$sortname&sortdir=$sortdir";
@@ -580,7 +586,7 @@ sub generate_report {
     $row->{balance}->{data}        = $data;
     $row->{projectnumbers}->{data} = join ", ", sort { lc($a) cmp lc($b) } keys %{ $ref->{projectnumbers} };
 
-    map { $row->{$_}->{data} = $ref->{$_} } qw(id reference description notes gldate employee department);
+    map { $row->{$_}->{data} = $ref->{$_} } qw(id reference description notes gldate employee department transaction_description);
 
     map { $row->{$_}->{data} = \@{ $rows{$_} }; } qw(transdate debit credit debit_accno credit_accno debit_tax_accno credit_tax_accno source);
 
@@ -969,12 +975,21 @@ sub setup_gl_action_bar {
   my $form   = $::form;
   my $change_never            = $::instance_conf->get_gl_changeable == 0;
   my $change_on_same_day_only = $::instance_conf->get_gl_changeable == 2 && ($form->current_date(\%::myconfig) ne $form->{gldate});
-  my $is_linked_bank_transaction;
+  my ($is_linked_bank_transaction, $is_linked_ap_transaction, $is_reconciled_bank_transaction);
 
   if ($form->{id} && SL::DB::Manager::BankTransactionAccTrans->find_by(gl_id => $form->{id})) {
     $is_linked_bank_transaction = 1;
   }
-
+  if ($form->{id} && SL::DB::Manager::ApGl->find_by(gl_id => $form->{id})) {
+    $is_linked_ap_transaction = 1;
+  }
+  # dont edit reconcilated bookings!
+  if ($form->{id}) {
+    my @acc_trans = map { $_->acc_trans_id } @{ SL::DB::Manager::AccTransaction->get_all( where => [ trans_id => $form->{id} ] ) };
+    if (scalar @acc_trans && scalar @{ SL::DB::Manager::ReconciliationLink->get_all(where => [ acc_trans_id  => [ @acc_trans ] ]) }) {
+      $is_reconciled_bank_transaction = 1;
+    }
+  }
   my $create_post_action = sub {
     # $_[0]: description
     # $_[1]: after_action
@@ -986,7 +1001,9 @@ sub setup_gl_action_bar {
                 : ($form->{id} && $change_never)            ? t8('Changing general ledger transaction has been disabled in the configuration.')
                 : ($form->{id} && $change_on_same_day_only) ? t8('General ledger transactions can only be changed on the day they are posted.')
                 : $is_linked_bank_transaction               ? t8('This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.')
-                :                                             undef,
+                : $is_linked_ap_transaction                 ? t8('This transaction is linked with a AP transaction. Please undo and redo the AP transaction booking if needed.')
+                : $is_reconciled_bank_transaction           ? t8('This transaction is reconciled with a bank transaction. Please undo the reconciliation if needed.')
+                : undef,
     ],
   };
 
@@ -1017,6 +1034,8 @@ sub setup_gl_action_bar {
           disabled => !$form->{id}                ? t8('This general ledger transaction has not been posted yet.')
                     : $form->{storno}             ? t8('A canceled general ledger transaction cannot be canceled again.')
                     : $is_linked_bank_transaction ? t8('This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.')
+                    : $is_linked_ap_transaction   ? t8('This transaction is linked with a AP transaction. Please undo and redo the AP transaction booking if needed.')
+                    : $is_reconciled_bank_transaction ? t8('This transaction is reconciled with a bank transaction. Please undo the reconciliation if needed.')
                     : undef,
         ],
         action => [ t8('Delete'),
@@ -1027,8 +1046,10 @@ sub setup_gl_action_bar {
                     : $change_never            ? t8('Changing invoices has been disabled in the configuration.')
                     : $change_on_same_day_only ? t8('Invoices can only be changed on the day they are posted.')
                     : $is_linked_bank_transaction ? t8('This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.')
+                    : $is_linked_ap_transaction   ? t8('This transaction is linked with a AP transaction. Please undo and redo the AP transaction booking if needed.')
+                    : $is_reconciled_bank_transaction ? t8('This transaction is reconciled with a bank transaction. Please undo the reconciliation if needed.')
                     : $form->{storno}             ? t8('A canceled general ledger transaction cannot be deleted.')
-                    :                            undef,
+                    : undef,
         ],
       ], # end of combobox "Storno"
 
@@ -1036,7 +1057,7 @@ sub setup_gl_action_bar {
         action => [ t8('more') ],
         action => [
           t8('History'),
-          call     => [ 'set_history_window', $form->{id} * 1, 'id' ],
+          call     => [ 'set_history_window', $form->{id} * 1, 'glid' ],
           disabled => !$form->{id} ? t8('This invoice has not been posted yet.') : undef,
         ],
         action => [
@@ -1053,7 +1074,7 @@ sub setup_gl_action_bar {
           call     => [ 'kivi.Draft.popup', 'gl', 'unknown', $form->{draft_id}, $form->{draft_description} ],
           disabled => $form->{id}     ? t8('This invoice has already been posted.')
                     : $form->{locked} ? t8('The billing period has already been locked.')
-                    :                   undef,
+                    : undef,
         ],
       ], # end of combobox "more"
     );
@@ -1112,7 +1133,7 @@ sub form_header {
 
   my ($init) = @_;
 
-  $::request->layout->add_javascripts("autocomplete_chart.js", "autocomplete_project.js", "kivi.File.js", "kivi.GL.js", "kivi.RecordTemplate.js", "kivi.Validator.js");
+  $::request->layout->add_javascripts("autocomplete_chart.js", "autocomplete_project.js", "kivi.File.js", "kivi.GL.js", "kivi.RecordTemplate.js", "kivi.Validator.js", "show_history.js");
 
   my @old_project_ids     = grep { $_ } map{ $::form->{"project_id_$_"} } 1..$::form->{rowcount};
   my @conditions          = @old_project_ids ? (id => \@old_project_ids) : ();
@@ -1207,9 +1228,10 @@ sub post_transaction {
   my $locale   = $main::locale;
 
   # check if there is something in reference and date
-  $form->isblank("reference",   $locale->text('Reference missing!'));
-  $form->isblank("transdate",   $locale->text('Transaction Date missing!'));
-  $form->isblank("description", $locale->text('Description missing!'));
+  $form->isblank("reference",               $locale->text('Reference missing!'));
+  $form->isblank("transdate",               $locale->text('Transaction Date missing!'));
+  $form->isblank("description",             $locale->text('Description missing!'));
+  $form->isblank("transaction_description", $locale->text('A transaction description is required.')) if $::instance_conf->get_require_transaction_description_ps;
 
   my $transdate = $form->datetonum($form->{transdate}, \%myconfig);
   my $closedto  = $form->datetonum($form->{closedto},  \%myconfig);
index 450d124..f3e7fe5 100644 (file)
@@ -185,6 +185,7 @@ sub generate_report {
     'microfiche'         => { 'text' => $locale->text('Microfiche'), },
     'name'               => { 'text' => $locale->text('Name'), },
     'onhand'             => { 'text' => $locale->text('Stocked Qty'), },
+    'assembly_qty'       => { 'text' => $locale->text('Assembly Item Qty'), },
     'ordnumber'          => { 'text' => $locale->text('Order Number'), },
     'partnumber'         => { 'text' => $locale->text('Part Number'), },
     'partsgroup'         => { 'text' => $locale->text('Partsgroup'), },
@@ -268,6 +269,7 @@ sub generate_report {
     obsolete      => $locale->text('Obsolete'),
     orphaned      => $locale->text('Orphaned'),
     onhand        => $locale->text('On Hand'),
+    assembly_qty  => $locale->text('Assembly Item Qty'),
     short         => $locale->text('Short'),
     onorder       => $locale->text('On Order'),
     ordered       => $locale->text('Ordered'),
@@ -389,7 +391,7 @@ sub generate_report {
 
   my @columns = qw(
     partnumber type_and_classific description notes partsgroup warehouse bin
-    make model onhand rop soldtotal unit listprice
+    make model assembly_qty onhand rop soldtotal unit listprice
     linetotallistprice sellprice linetotalsellprice lastcost assembly_lastcost linetotallastcost
     priceupdate weight image drawing microfiche invnumber ordnumber quonumber
     transdate name serialnumber deliverydate ean projectnumber projectdescription
@@ -418,7 +420,7 @@ sub generate_report {
 
   %column_defs = (%column_defs, %column_defs_cvars, %column_defs_pricegroups);
   map { $column_defs{$_}->{visible} ||= $form->{"l_$_"} ? 1 : 0 } @columns;
-  map { $column_defs{$_}->{align}   = 'right' } qw(onhand sellprice listprice lastcost assembly_lastcost linetotalsellprice linetotallastcost linetotallistprice rop weight soldtotal shop), @pricegroup_columns;
+  map { $column_defs{$_}->{align}   = 'right' } qw(assembly_qty onhand sellprice listprice lastcost assembly_lastcost linetotalsellprice linetotallastcost linetotallistprice rop weight soldtotal shop), @pricegroup_columns;
 
   my @hidden_variables = (
     qw(l_subtotal l_linetotal searchitems itemstatus bom l_pricegroups insertdatefrom insertdateto),
index fda1fd6..793099f 100644 (file)
@@ -54,10 +54,13 @@ use SL::IO;
 use SL::File;
 use SL::PriceSource;
 use SL::Presenter::Part;
+use SL::Util qw(trim);
 
+use SL::DB::AuthUser;
 use SL::DB::Contact;
 use SL::DB::Currency;
 use SL::DB::Customer;
+use SL::DB::DeliveryOrder::TypeData qw();
 use SL::DB::Default;
 use SL::DB::Language;
 use SL::DB::Printer;
@@ -170,6 +173,12 @@ sub display_row {
   my @row2_sort   = qw(
     serialnr projectnr reqdate subtotal marge listprice lastcost onhand
   );
+  # serialnr is important for delivery_orders
+  if ($form->{type} eq 'sales_delivery_order') {
+    splice @row2_sort, 0, 1;
+    splice @header_sort, 4, 0, "serialnr";
+  }
+
   my %column_def = (
     runningnumber => { width => 5,     value => $locale->text('No.'),                  display => 1, },
     partnumber    => { width => 8,     value => $locale->text('Number'),               display => 1, },
@@ -1197,6 +1206,15 @@ sub print_form {
   if ($form->{formname} eq "invoice") {
     $form->{label} = $locale->text('Invoice');
   }
+
+  if ($form->{formname} eq "invoice_for_advance_payment") {
+    $form->{label} = $locale->text('Invoice for Advance Payment');
+  }
+
+  if ($form->{formname} eq "final_invoice") {
+    $form->{label} = $locale->text('Final Invoice');
+  }
+
   if ($form->{formname} eq 'sales_order') {
     $inv                  = "ord";
     $due                  = "req";
@@ -1294,7 +1312,7 @@ sub print_form {
   }
 
   $form->{TEMPLATE_DRIVER_OPTIONS} = { };
-  if (any { $form->{type} eq $_ } qw(sales_quotation sales_order sales_delivery_order invoice request_quotation purchase_order purchase_delivery_order credit_note)) {
+  if (any { $form->{type} eq $_ } qw(sales_quotation sales_order sales_delivery_order invoice invoice_for_advance_payment final_invoice request_quotation purchase_order purchase_delivery_order credit_note)) {
     $form->{TEMPLATE_DRIVER_OPTIONS}->{variable_content_types} = $form->get_variable_content_types();
   }
 
@@ -1386,6 +1404,8 @@ sub print_form {
     $form->get_shipto(\%myconfig);
   }
 
+  $form->set_addition_billing_address_print_variables;
+
   $form->{notes} =~ s/^\s+//g;
 
   delete $form->{printer_command};
@@ -1564,6 +1584,10 @@ sub print_form {
     today     => DateTime->today,
   };
 
+  if ($defaults->print_interpolate_variables_in_positions) {
+    $form->substitute_placeholders_in_template_arrays({ field => 'description', type => 'text' }, { field => 'longdescription', type => 'html' });
+  }
+
   $form->parse_template(\%myconfig);
 
   $form->{callback} = "";
@@ -1871,6 +1895,8 @@ sub _make_record_item {
     sales_quotation         => 'OrderItem',
     request_quotation       => 'OrderItem',
     invoice                 => 'InvoiceItem',
+    invoice_for_advance_payment => 'InvoiceItem',
+    final_invoice           => 'InvoiceItem',
     credit_note             => 'InvoiceItem',
     purchase_invoice        => 'InvoiceItem',
     purchase_delivery_order => 'DeliveryOrderItem',
@@ -1993,7 +2019,10 @@ sub _make_record {
   }
 
   $obj->items(@items) if @items;
-  $obj->is_sales(!!$obj->customer_id) if $class eq 'SL::DB::DeliveryOrder';
+
+  if ($class eq 'SL::DB::DeliveryOrder' && !$obj->order_type) {
+    $obj->order_type(SL::DB::DeliveryOrder::TypeData::validate_type($::form->{type}));
+  }
 
   if ($class eq 'SL::DB::Invoice') {
     my $paid = $factor *
@@ -2101,7 +2130,11 @@ sub show_sales_purchase_email_dialog {
     $body_params{fallback_translation_type} = "preset_text_invoice";
   }
 
-  $::form->{all_employees} = SL::DB::Manager::Employee->get_all(query => [ deleted => 0 ]);
+  my @employees_with_email = grep {
+    my $user = SL::DB::Manager::AuthUser->find_by(login => $_->login);
+    $user && !!trim($user->get_config_value('email'));
+  } @{ SL::DB::Manager::Employee->get_all_sorted(query => [ deleted => 0 ]) };
+
   my $email_form = {
     to                  => $email,
     cc                  => $email_cc,
@@ -2112,13 +2145,19 @@ sub show_sales_purchase_email_dialog {
   };
 
   my %files = _get_files_for_email_dialog();
+
+  my $all_partner_email_addresses;
+  $all_partner_email_addresses = SL::DB::Customer->load_cached($::form->{vc_id})->get_all_email_addresses() if 'customer' eq $::form->{vc};
+  $all_partner_email_addresses = SL::DB::Vendor  ->load_cached($::form->{vc_id})->get_all_email_addresses() if 'vendor'   eq $::form->{vc};
+
   my $html  = $::form->parse_html_template("common/_send_email_dialog", {
-    email_form  => $email_form,
-    show_bcc    => $::auth->assert('email_bcc', 'may fail'),
-    FILES       => \%files,
-    is_customer => $::form->{vc} eq 'customer',
+    email_form      => $email_form,
+    show_bcc        => $::auth->assert('email_bcc', 'may fail'),
+    FILES           => \%files,
+    is_customer     => $::form->{vc} eq 'customer',
     is_invoice_mail => ($record_email && $::form->{type} eq 'invoice'),
-    ALL_EMPLOYEES   => $::form->{all_employees},
+    ALL_EMPLOYEES   => \@employees_with_email,
+    ALL_PARTNER_EMAIL_ADDRESSES => $all_partner_email_addresses,
   });
 
   print $::form->ajax_response_header, $html;
@@ -2132,13 +2171,30 @@ sub send_sales_purchase_email {
                   :                                                    'is.pl';
 
   my $email_form  = delete $::form->{email_form};
+
+  if ($email_form->{additional_to}) {
+    $email_form->{to} = join ', ', grep { $_ } $email_form->{to}, @{$email_form->{additional_to}};
+    delete $email_form->{additional_to};
+  }
+
   my %field_names = (to => 'email');
 
   $::form->{ $field_names{$_} // $_ } = $email_form->{$_} for keys %{ $email_form };
 
   $::form->{media} = 'email';
 
-  if (($::form->{attachment_policy} // '') =~ m{^(?:old_file|no_file)$}) {
+  $::form->{attachment_policy} //= '';
+
+  # Is an old file version available?
+  my $attfile;
+  if ($::form->{attachment_policy} eq 'old_file') {
+    $attfile = SL::File->get_all(object_id     => $id,
+                                 object_type   => $type,
+                                 file_type     => 'document',
+                                 print_variant => $::form->{formname},);
+  }
+
+  if ($::form->{attachment_policy} eq 'no_file' || ($::form->{attachment_policy} eq 'old_file' && $attfile)) {
     $::form->send_email(\%::myconfig, 'pdf');
 
   } else {
@@ -2183,3 +2239,35 @@ sub _maybe_attach_zugferd_data {
     $::form->error($e->message);
   }
 }
+
+sub download_factur_x_xml {
+  my ($form) = @_;
+
+  my $record = _make_record();
+
+  die if !$record
+      || !$record->can('customer')
+      || !$record->customer
+      || !$record->can('create_pdf_a_print_options')
+      || !$record->can('create_zugferd_data')
+      || !$record->customer->create_zugferd_invoices_for_this_customer;
+
+  my $xml_content = eval { $record->create_zugferd_data };
+
+  if (my $e = SL::X::ZUGFeRDValidation->caught) {
+    $::form->error($e->message);
+  }
+
+  my $attachment_filename = $::form->generate_attachment_filename;
+  $attachment_filename    =~ s{\.[^.]+$}{.xml};
+  my %headers             = (
+    '-type'           => 'application/xml',
+    '-connection'     => 'close',
+    '-attachment'     => $attachment_filename,
+    '-content-length' => length($xml_content),
+  );
+
+  print $::request->cgi->header(%headers);
+
+  $::locale->with_raw_io(\*STDOUT, sub { print $xml_content });
+}
index cca6d12..b0df30c 100644 (file)
@@ -34,6 +34,7 @@
 
 use SL::FU;
 use SL::Helper::Flash qw(flash_later);
+use SL::Helper::UserPreferences::DisplayPreferences;
 use SL::IR;
 use SL::IS;
 use SL::DB::BankTransactionAccTrans;
@@ -56,9 +57,10 @@ use strict;
 # end of main
 
 sub _may_view_or_edit_this_invoice {
-  return 1 if  $::auth->assert('ap_transactions', 1); # may edit all invoices
-  return 0 if !$::form->{id};                         # creating new invoices isn't allowed without invoice_edit
-  return 0 if !$::form->{globalproject_id};           # existing records without a project ID are not allowed
+  return 1 if  $::auth->assert('ap_transactions', 1);       # may edit all invoices
+  return 0 if !$::form->{id};                               # creating new invoices isn't allowed without invoice_edit
+  return 1 if  $::auth->assert('purchase_invoice_view', 1); # viewing is allowed with this right
+  return 0 if !$::form->{globalproject_id};                 # existing records without a project ID are not allowed
   return SL::DB::Project->new(id => $::form->{globalproject_id})->load->may_employee_view_project_invoices(SL::DB::Manager::Employee->current);
 }
 
@@ -455,9 +457,10 @@ sub form_header {
     $form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
   }
 
-  $TMPL_VAR{is_format_html}      = $form->{format} eq 'html';
-  $TMPL_VAR{dateformat}          = $myconfig{dateformat};
-  $TMPL_VAR{numberformat}        = $myconfig{numberformat};
+  $TMPL_VAR{is_format_html}                         = $form->{format} eq 'html';
+  $TMPL_VAR{dateformat}                             = $myconfig{dateformat};
+  $TMPL_VAR{numberformat}                           = $myconfig{numberformat};
+  $TMPL_VAR{longdescription_dialog_size_percentage} = SL::Helper::UserPreferences::DisplayPreferences->new()->get_longdescription_dialog_size_percentage();
 
   # hiddens
   $TMPL_VAR{HIDDENS} = [qw(
index 31f9c74..d0e2506 100644 (file)
 use SL::FU;
 use SL::IS;
 use SL::OE;
+use SL::Helper::UserPreferences::DisplayPreferences;
 use SL::MoreCommon qw(restore_form save_form);
+use SL::RecordLinks;
+
 use Data::Dumper;
 use DateTime;
-use List::MoreUtils qw(uniq);
+use List::MoreUtils qw(any uniq);
 use List::Util qw(max sum);
 use List::UtilsBy qw(sort_by);
 use English qw(-no_match_vars);
@@ -60,9 +63,10 @@ use strict;
 # end of main
 
 sub _may_view_or_edit_this_invoice {
-  return 1 if  $::auth->assert('invoice_edit', 1); # may edit all invoices
-  return 0 if !$::form->{id};                      # creating new invoices isn't allowed without invoice_edit
-  return 0 if !$::form->{globalproject_id};        # existing records without a project ID are not allowed
+  return 1 if  $::auth->assert('invoice_edit', 1);       # may edit all invoices
+  return 0 if !$::form->{id};                            # creating new invoices isn't allowed without invoice_edit
+  return 1 if  $::auth->assert('sales_invoice_view', 1); # viewing is allowed with this right
+  return 0 if !$::form->{globalproject_id};              # existing records without a project ID are not allowed
   return SL::DB::Project->new(id => $::form->{globalproject_id})->load->may_employee_view_project_invoices(SL::DB::Manager::Employee->current);
 }
 
@@ -89,6 +93,13 @@ sub add {
     if ($form->{storno}) {
       $form->{title} = $locale->text('Add Storno Credit Note');
     }
+
+  } elsif ($form->{type} eq "invoice_for_advance_payment") {
+    $form->{title} = $locale->text('Add Invoice for Advance Payment');
+
+  } elsif ($form->{type} eq "final_invoice") {
+    $form->{title} = $locale->text('Add Final Invoice');
+
   } else {
     $form->{title} = $locale->text('Add Sales Invoice');
 
@@ -97,7 +108,7 @@ sub add {
 
   $form->{callback} = "$form->{script}?action=add&type=$form->{type}" unless $form->{callback};
 
-  &invoice_links;
+  invoice_links(is_new => 1);
   &prepare_invoice;
   &display_form;
 
@@ -132,6 +143,14 @@ sub edit {
   if ($form->{type} eq "credit_note") {
     $form->{title} = $locale->text('Edit Credit Note');
     $form->{title} = $locale->text('Edit Storno Credit Note') if $form->{storno};
+
+  } elsif ($form->{type} eq "invoice_for_advance_payment") {
+    $form->{title} = $locale->text('Edit Invoice for Advance Payment');
+    $form->{title} = $locale->text('Edit Storno Invoice for Advance Payment') if $form->{storno};
+
+  } elsif ($form->{type} eq "final_invoice") {
+    $form->{title} = $locale->text('Edit Final Invoice');
+
   } else {
     $form->{title} = $locale->text('Edit Sales Invoice');
     $form->{title} = $locale->text('Edit Storno Invoice')     if $form->{storno};
@@ -154,6 +173,7 @@ sub invoice_links {
   # Delay access check to after the invoice's been loaded so that
   # project-specific invoice rights can be evaluated.
 
+  my %params   = @_;
   my $form     = $main::form;
   my %myconfig = %main::myconfig;
 
@@ -172,6 +192,8 @@ sub invoice_links {
 
   IS->get_customer(\%myconfig, \%$form);
 
+  $form->{billing_address_id} = $form->{default_billing_address_id} if $params{is_new};
+
   $form->restore_vars(qw(id));
 
   IS->retrieve_invoice(\%myconfig, \%$form);
@@ -234,8 +256,18 @@ sub prepare_invoice {
   if ($form->{type} eq "credit_note") {
     $form->{type}     = "credit_note";
     $form->{formname} = "credit_note";
+
+  } elsif ($form->{type} eq "invoice_for_advance_payment") {
+    $form->{type}     = "invoice_for_advance_payment";
+    $form->{formname} = "invoice_for_advance_payment";
+
+  } elsif ($form->{type} eq "final_invoice") {
+    $form->{type}     = "final_invoice";
+    $form->{formname} = "final_invoice";
+
   } elsif ($form->{formname} eq "proforma" ) {
     $form->{type}     = "invoice";
+
   } else {
     $form->{type}     = "invoice";
     $form->{formname} = "invoice";
@@ -273,19 +305,45 @@ sub prepare_invoice {
 }
 
 sub setup_is_action_bar {
+  my ($tmpl_var)              = @_;
   my $form                    = $::form;
   my $change_never            = $::instance_conf->get_is_changeable == 0;
   my $change_on_same_day_only = $::instance_conf->get_is_changeable == 2 && ($form->current_date(\%::myconfig) ne $form->{gldate});
   my $payments_balanced       = ($::form->{oldtotalpaid} == 0);
   my $has_storno              = ($::form->{storno} && !$::form->{storno_id});
   my $may_edit_create         = $::auth->assert('invoice_edit', 1);
-  my $is_linked_bank_transaction;
+  my $factur_x_enabled        = $tmpl_var->{invoice_obj} && $tmpl_var->{invoice_obj}->customer->create_zugferd_invoices_for_this_customer;
+  my ($is_linked_bank_transaction, $warn_unlinked_delivery_order);
     if ($::form->{id}
         && SL::DB::Default->get->payments_changeable != 0
         && SL::DB::Manager::BankTransactionAccTrans->find_by(ar_id => $::form->{id})) {
 
       $is_linked_bank_transaction = 1;
     }
+  if ($::instance_conf->get_warn_no_delivery_order_for_invoice && !$form->{id}) {
+    $warn_unlinked_delivery_order = 1 unless $form->{convert_from_do_ids};
+  }
+
+  my $has_further_invoice_for_advance_payment;
+  if ($form->{id} && $form->{type} eq "invoice_for_advance_payment") {
+    my $invoice_obj = SL::DB::Invoice->load_cached($form->{id});
+    my $lr          = $invoice_obj->linked_records(direction => 'to', to => ['Invoice']);
+    $has_further_invoice_for_advance_payment = any {'SL::DB::Invoice' eq ref $_ && "invoice_for_advance_payment" eq $_->type} @$lr;
+  }
+
+  my $has_final_invoice;
+  if ($form->{id} && $form->{type} eq "invoice_for_advance_payment") {
+    my $invoice_obj = SL::DB::Invoice->load_cached($form->{id});
+    my $lr          = $invoice_obj->linked_records(direction => 'to', to => ['Invoice']);
+    $has_final_invoice = any {'SL::DB::Invoice' eq ref $_ && "final_invoice" eq $_->invoice_type} @$lr;
+  }
+
+  my $is_invoice_for_advance_payment_from_order;
+  if ($form->{id} && $form->{type} eq "invoice_for_advance_payment") {
+    my $invoice_obj = SL::DB::Invoice->load_cached($form->{id});
+    my $lr          = $invoice_obj->linked_records(direction => 'from', from => ['Order']);
+    $is_invoice_for_advance_payment_from_order = scalar @$lr >= 1;
+  }
 
   for my $bar ($::request->layout->get('actionbar')) {
     $bar->add(
@@ -304,6 +362,7 @@ sub setup_is_action_bar {
           t8('Post'),
           submit   => [ '#form', { action => "post" } ],
           checks   => [ 'kivi.validate_form' ],
+          confirm  => t8('The invoice is not linked with a sales delivery order. Post anyway?') x !!$warn_unlinked_delivery_order,
           disabled => !$may_edit_create                         ? t8('You must not change this invoice.')
                     : $form->{locked}                           ? t8('The billing period has already been locked.')
                     : $form->{storno}                           ? t8('A canceled invoice cannot be posted.')
@@ -320,6 +379,7 @@ sub setup_is_action_bar {
                     : !$form->{id}                ? t8('This invoice has not been posted yet.')
                     : $is_linked_bank_transaction ? t8('This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.')
                     :                               undef,
+          only_if  => $form->{type} ne "invoice_for_advance_payment",
         ],
         action => [ t8('Mark as paid'),
           submit   => [ '#form', { action => "mark_as_paid" } ],
@@ -327,7 +387,7 @@ sub setup_is_action_bar {
           disabled => !$may_edit_create ? t8('You must not change this invoice.')
                     : !$form->{id}      ? t8('This invoice has not been posted yet.')
                     :                     undef,
-          only_if  => $::instance_conf->get_is_show_mark_as_paid,
+          only_if  => ($::instance_conf->get_is_show_mark_as_paid && $form->{type} ne "invoice_for_advance_payment") || $form->{type} eq 'final_invoice',
         ],
       ], # end of combobox "Post"
 
@@ -369,6 +429,30 @@ sub setup_is_action_bar {
                     : !$form->{id}      ? t8('This invoice has not been posted yet.')
                     :                     undef,
         ],
+        action => [
+          t8('Further Invoice for Advance Payment'),
+          submit   => [ '#form', { action => "further_invoice_for_advance_payment" } ],
+          checks   => [ 'kivi.validate_form' ],
+          disabled => !$may_edit_create                          ? t8('You must not change this invoice.')
+                    : !$form->{id}                               ? t8('This invoice has not been posted yet.')
+                    : $has_further_invoice_for_advance_payment   ? t8('This invoice has already a further invoice for advanced payment.')
+                    : $has_final_invoice                         ? t8('This invoice has already a final invoice.')
+                    : $is_invoice_for_advance_payment_from_order ? t8('This invoice was added from an order. See there.')
+                    :                                              undef,
+          only_if  => $form->{type} eq "invoice_for_advance_payment",
+        ],
+        action => [
+          t8('Final Invoice'),
+          submit   => [ '#form', { action => "final_invoice" } ],
+          checks   => [ 'kivi.validate_form' ],
+          disabled => !$may_edit_create                          ? t8('You must not change this invoice.')
+                    : !$form->{id}                               ? t8('This invoice has not been posted yet.')
+                    : $has_further_invoice_for_advance_payment   ? t8('This invoice has a further invoice for advanced payment.')
+                    : $has_final_invoice                         ? t8('This invoice has already a final invoice.')
+                    : $is_invoice_for_advance_payment_from_order ? t8('This invoice was added from an order. See there.')
+                    :                                              undef,
+          only_if  => $form->{type} eq "invoice_for_advance_payment",
+        ],
         action => [
           t8('Credit Note'),
           submit   => [ '#form', { action => "credit_note" } ],
@@ -398,8 +482,9 @@ sub setup_is_action_bar {
                     :                                   undef,
         ],
         action => [ t8('Print and Post'),
-          call     => [ 'kivi.SalesPurchase.show_print_dialog', $form->{id} ? 'print' : 'print_and_post' ],
+          call     => [ 'kivi.SalesPurchase.show_print_dialog', 'print_and_post' ],
           checks   => [ 'kivi.validate_form' ],
+          confirm  => t8('The invoice is not linked with a sales delivery order. Post anyway?') x !!$warn_unlinked_delivery_order,
           disabled => !$may_edit_create                         ? t8('You must not change this invoice.')
                     : $form->{locked}                           ? t8('The billing period has already been locked.')
                     : $form->{storno}                           ? t8('A canceled invoice cannot be posted.')
@@ -416,6 +501,14 @@ sub setup_is_action_bar {
                     : $form->{postal_invoice} ? t8('This customer wants a postal invoices.')
                     :                     undef,
         ],
+        action => [ t8('Factur-X/ZUGFeRD'),
+          submit   => [ '#form', { action => "download_factur_x_xml" } ],
+          checks   => [ 'kivi.validate_form' ],
+          disabled => !$may_edit_create  ? t8('You must not print this invoice.')
+                    : !$form->{id}       ? t8('This invoice has not been posted yet.')
+                    : !$factur_x_enabled ? t8('Creating Factur-X/ZUGFeRD invoices is not enabled for this customer.')
+                    :                      undef,
+        ],
       ], # end of combobox "Export"
 
       combobox => [
@@ -533,10 +626,12 @@ sub form_header {
     $form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
   }
 
-  $TMPL_VAR{is_type_credit_note} = $form->{type}   eq "credit_note";
-  $TMPL_VAR{is_format_html}      = $form->{format} eq 'html';
-  $TMPL_VAR{dateformat}          = $myconfig{dateformat};
-  $TMPL_VAR{numberformat}        = $myconfig{numberformat};
+  $TMPL_VAR{is_type_normal_invoice}                 = $form->{type} eq "invoice";
+  $TMPL_VAR{is_type_credit_note}                    = $form->{type}   eq "credit_note";
+  $TMPL_VAR{is_format_html}                         = $form->{format} eq 'html';
+  $TMPL_VAR{dateformat}                             = $myconfig{dateformat};
+  $TMPL_VAR{numberformat}                           = $myconfig{numberformat};
+  $TMPL_VAR{longdescription_dialog_size_percentage} = SL::Helper::UserPreferences::DisplayPreferences->new()->get_longdescription_dialog_size_percentage();
 
   # hiddens
   $TMPL_VAR{HIDDENS} = [qw(
@@ -555,7 +650,7 @@ sub form_header {
   $TMPL_VAR{payment_terms_obj} = get_payment_terms_for_invoice();
   $form->{duedate}             = $TMPL_VAR{payment_terms_obj}->calc_date(reference_date => $form->{invdate}, due_date => $form->{duedate})->to_kivitendo if $TMPL_VAR{payment_terms_obj};
 
-  setup_is_action_bar();
+  setup_is_action_bar(\%TMPL_VAR);
 
   $form->header();
 
@@ -676,17 +771,18 @@ sub form_footer {
   }
 
   print $form->parse_html_template('is/form_footer', {
-    is_type_credit_note => ($form->{type} eq "credit_note"),
-    totalpaid           => $totalpaid,
-    paid_missing        => $form->{invtotal} - $totalpaid,
-    print_options       => setup_sales_purchase_print_options(),
-    show_storno         => $form->{id} && !$form->{storno} && !IS->has_storno(\%myconfig, $form, "ar") && !$totalpaid,
-    show_delete         => ($::instance_conf->get_is_changeable == 2)
-                             ? ($form->current_date(\%myconfig) eq $form->{gldate})
-                             : ($::instance_conf->get_is_changeable == 1),
-    today               => DateTime->today,
-    vc_obj              => $form->{customer_id} ? SL::DB::Customer->load_cached($form->{customer_id}) : undef,
-    shipto_cvars        => $shipto_cvars,
+    is_type_normal_invoice              => ($form->{type} eq "invoice"),
+    is_type_credit_note                 => ($form->{type} eq "credit_note"),
+    totalpaid                           => $totalpaid,
+    paid_missing                        => $form->{invtotal} - $totalpaid,
+    print_options                       => setup_sales_purchase_print_options(),
+    show_storno                         => $form->{id} && !$form->{storno} && !IS->has_storno(\%myconfig, $form, "ar") && !$totalpaid,
+    show_delete                         => ($::instance_conf->get_is_changeable == 2)
+                                             ? ($form->current_date(\%myconfig) eq $form->{gldate})
+                                             : ($::instance_conf->get_is_changeable == 1),
+    today                               => DateTime->today,
+    vc_obj                              => $form->{customer_id} ? SL::DB::Customer->load_cached($form->{customer_id}) : undef,
+    shipto_cvars                        => $shipto_cvars,
   });
 ##print $form->parse_html_template('is/_payments'); # parser
 ##print $form->parse_html_template('webdav/_list'); # parser
@@ -727,6 +823,7 @@ sub update {
     $::form->{salesman_id} = SL::DB::Manager::Employee->current->id if exists $::form->{salesman_id};
 
     IS->get_customer(\%myconfig, $form);
+    $::form->{billing_address_id} = $::form->{default_billing_address_id};
   }
 
   $form->{taxincluded} ||= $taxincluded;
@@ -949,6 +1046,14 @@ sub post {
 
   $form->isblank("exchangerate", $locale->text('Exchangerate missing!'))
     if ($form->{currency} ne $form->{defaultcurrency});
+  # advance payment allows only one tax
+  if ($form->{type} eq 'invoice_for_advance_payment') {
+    my @current_taxaccounts = (split(/ /, $form->{taxaccounts}));
+    $form->error($locale->text('Cannot post invoice for advance payment with more than one tax'))
+      if (scalar @current_taxaccounts > 1);
+    $form->error($locale->text('Cannot post invoice for advance payment with taxincluded'))
+      if ($form->{taxincluded});
+  }
 
   for my $i (1 .. $form->{paidaccounts}) {
     if ($form->parse_amount(\%myconfig, $form->{"paid_$i"})) {
@@ -1093,6 +1198,80 @@ sub use_as_new {
   $main::lxdebug->leave_sub();
 }
 
+sub further_invoice_for_advance_payment {
+  my $form     = $main::form;
+  my %myconfig = %main::myconfig;
+
+  $main::auth->assert('invoice_edit');
+
+  delete @{ $form }{qw(printed emailed queued invnumber invdate exchangerate forex deliverydate datepaid_1 gldate_1 acc_trans_id_1 source_1 memo_1 paid_1 exchangerate_1 AP_paid_1 storno locked)};
+  $form->{convert_from_ar_ids} = $form->{id};
+  $form->{id}                  = '';
+  $form->{rowcount}--;
+  $form->{paidaccounts}        = 1;
+  $form->{invdate}             = $form->current_date(\%myconfig);
+  my $terms                    = get_payment_terms_for_invoice();
+  $form->{duedate}             = $terms ? $terms->calc_date(reference_date => $form->{invdate})->to_kivitendo : $form->{invdate};
+  $form->{employee_id}         = SL::DB::Manager::Employee->current->id;
+  $form->{forex}               = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, 'buy');
+  $form->{exchangerate}        = $form->{forex} if $form->{forex};
+
+  $form->{"converted_from_invoice_id_$_"} = delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
+
+  &display_form;
+}
+
+sub final_invoice {
+  my $form     = $main::form;
+  my %myconfig = %main::myconfig;
+
+  $main::auth->assert('invoice_edit');
+
+  my $related_invoices = IS->_get_invoices_for_advance_payment($form->{id});
+
+  delete @{ $form }{qw(printed emailed queued invnumber invdate exchangerate forex deliverydate datepaid_1 gldate_1 acc_trans_id_1 source_1 memo_1 paid_1 exchangerate_1 AP_paid_1 storno locked)};
+
+  $form->{convert_from_ar_ids} = $form->{id};
+  $form->{id}                  = '';
+  $form->{type}                = 'final_invoice';
+  $form->{title}               = t8('Edit Final Invoice');
+  $form->{paidaccounts}        = 1;
+  $form->{invdate}             = $form->current_date(\%myconfig);
+  my $terms                    = get_payment_terms_for_invoice();
+  $form->{duedate}             = $terms ? $terms->calc_date(reference_date => $form->{invdate})->to_kivitendo : $form->{invdate};
+  $form->{employee_id}         = SL::DB::Manager::Employee->current->id;
+  $form->{forex}               = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, 'buy');
+  $form->{exchangerate}        = $form->{forex} if $form->{forex};
+
+  foreach my $i (1 .. $form->{"rowcount"}) {
+    delete $form->{"id_$i"};
+    delete $form->{"invoice_id_$i"};
+    delete $form->{"parts_id_$i"};
+    delete $form->{"partnumber_$i"};
+    delete $form->{"description_$i"};
+  }
+
+  remove_emptied_rows(1);
+
+  my $i = 0;
+  foreach my $ri (@$related_invoices) {
+    foreach my $item (@{$ri->items_sorted}) {
+      $i++;
+      $form->{"id_$i"}         = $item->parts_id;
+      $form->{"partnumber_$i"} = $item->part->partnumber;
+      $form->{"discount_$i"}   = $item->discount*100.0;
+      $form->{"sellprice_$i"}  = $item->fxsellprice;
+      $form->{$_ . "_" . $i}   = $item->$_       for qw(description longdescription qty price_factor_id unit active_price_source active_discount_source);
+
+      $form->{$_ . "_" . $i}   = $form->format_amount(\%myconfig, $form->{$_ . "_" . $i}) for qw(qty sellprice discount);
+    }
+  }
+  $form->{rowcount} = $i;
+
+  update();
+  $::dispatcher->end_request;
+}
+
 sub storno {
   $main::lxdebug->enter_sub();
 
@@ -1222,7 +1401,6 @@ sub credit_note {
 
   &prepare_invoice;
 
-
   &display_form;
 
   $main::lxdebug->leave_sub();
index 890cf50..fe00085 100644 (file)
@@ -56,8 +56,9 @@ sub company_logo {
   my $git             = SL::Git->new;
   ($form->{git_head}) = $git->get_log(since => 'HEAD~1', until => 'HEAD') if $git->is_git_installation;
   $form->{xmas}       = '_xmas' if (DateTime->today->month == 12 && DateTime->today->day < 27);
-  $form->{xmas}       = '_corona' if (DateTime->today->month >= 7 && DateTime->today->year == 2020
-                                      && DateTime->today->month <= 11);
+  $form->{xmas}       = '_mir'  if (DateTime->today->month >= 3 && DateTime->today->year == 2022
+                                    && DateTime->today->month <= 9);
+  $form->{xmas}       = '_mir'  if (DateTime->today->day == 24 && DateTime->today->month == 2);
 
   # create the logo screen
   $form->header() unless $form->{noheader};
index 2f3803b..d859335 100644 (file)
@@ -42,6 +42,7 @@ use SL::FU;
 use SL::OE;
 use SL::IR;
 use SL::IS;
+use SL::Helper::UserPreferences::DisplayPreferences;
 use SL::MoreCommon qw(ary_diff restore_form save_form);
 use SL::ReportGenerator;
 use SL::YAML;
@@ -50,7 +51,6 @@ use List::Util qw(min max reduce sum);
 use Data::Dumper;
 
 use SL::Controller::Order;
-
 use SL::DB::Customer;
 use SL::DB::TaxZone;
 use SL::DB::PaymentTerm;
@@ -84,10 +84,18 @@ my $oe_access_map = {
   'sales_quotation'   => 'sales_quotation_edit',
 };
 
+my $oe_view_access_map = {
+  'sales_order'       => 'sales_order_edit       | sales_order_view',
+  'purchase_order'    => 'purchase_order_edit    | purchase_order_view',
+  'request_quotation' => 'request_quotation_edit | request_quotation_view',
+  'sales_quotation'   => 'sales_quotation_edit   | sales_quotation_view',
+};
+
 sub check_oe_access {
+  my (%params) = @_;
   my $form     = $main::form;
 
-  my $right   = $oe_access_map->{$form->{type}};
+  my $right   = ($params{with_view}) ? $oe_view_access_map->{$form->{type}} : $oe_access_map->{$form->{type}};
   $right    ||= 'DOES_NOT_EXIST';
 
   $main::auth->assert($right);
@@ -160,7 +168,7 @@ sub add {
 
   $form->{show_details} = $::myconfig{show_form_details};
 
-  &order_links;
+  order_links(is_new => 1);
   &prepare_order;
   &display_form;
 
@@ -245,6 +253,8 @@ sub edit {
 sub order_links {
   $main::lxdebug->enter_sub();
 
+  my (%params) = @_;
+
   my $form     = $main::form;
   my %myconfig = %main::myconfig;
   my $locale   = $main::locale;
@@ -266,8 +276,12 @@ sub order_links {
   $form->backup_vars(qw(payment_id language_id taxzone_id salesman_id taxincluded cp_id intnotes shipto_id delivery_term_id currency));
 
   # get customer / vendor
-  IR->get_vendor(\%myconfig, \%$form)   if $form->{type} =~ /(purchase_order|request_quotation)/;
-  IS->get_customer(\%myconfig, \%$form) if $form->{type} =~ /sales_(order|quotation)/;
+  if ($form->{type} =~ /(purchase_order|request_quotation)/) {
+    IR->get_vendor(\%myconfig, \%$form);
+  } else {
+    IS->get_customer(\%myconfig, \%$form);
+    $form->{billing_address_id} = $form->{default_billing_address_id} if $params{is_new};
+  }
 
   $form->restore_vars(qw(payment_id language_id taxzone_id intnotes cp_id shipto_id delivery_term_id));
   $form->restore_vars(qw(currency))    if $form->{id};
@@ -608,8 +622,9 @@ sub form_header {
   }
 
   $::request->{layout}->add_javascripts_inline("\$(function(){$dispatch_to_popup});");
-  $TMPL_VAR->{dateformat}          = $myconfig{dateformat};
-  $TMPL_VAR->{numberformat}        = $myconfig{numberformat};
+  $TMPL_VAR->{dateformat}                             = $myconfig{dateformat};
+  $TMPL_VAR->{numberformat}                           = $myconfig{numberformat};
+  $TMPL_VAR->{longdescription_dialog_size_percentage} = SL::Helper::UserPreferences::DisplayPreferences->new()->get_longdescription_dialog_size_percentage();
 
   if ($form->{type} eq 'sales_order') {
     if (!$form->{periodic_invoices_config}) {
@@ -775,8 +790,12 @@ sub update {
   if (($form->{"previous_${vc}_id"} || $form->{"${vc}_id"}) != $form->{"${vc}_id"}) {
     $::form->{salesman_id} = SL::DB::Manager::Employee->current->id if exists $::form->{salesman_id};
 
-    IS->get_customer(\%myconfig, $form) if $vc eq 'customer';
-    IR->get_vendor(\%myconfig, $form)   if $vc eq 'vendor';
+    if ($vc eq 'customer') {
+      IS->get_customer(\%myconfig, $form);
+      $::form->{billing_address_id} = $::form->{default_billing_address_id};
+    } else {
+      IR->get_vendor(\%myconfig, $form);
+    }
   }
 
   if (!$form->{forex}) {        # read exchangerate from input field (not hidden)
@@ -916,7 +935,7 @@ sub search {
   my %myconfig = %main::myconfig;
   my $locale   = $main::locale;
 
-  check_oe_access();
+  check_oe_access(with_view => 1);
 
   if ($form->{type} eq 'purchase_order') {
     $form->{vc}        = 'vendor';
@@ -1007,7 +1026,7 @@ sub orders {
   my $cgi      = $::request->{cgi};
 
   my %params   = @_;
-  check_oe_access();
+  check_oe_access(with_view => 1);
 
   my $ordnumber = ($form->{type} =~ /_order$/) ? "ordnumber" : "quonumber";
 
@@ -1083,7 +1102,7 @@ sub orders {
                                                         reqdatefrom reqdateto projectnumber project_id periodic_invoices_active periodic_invoices_inactive
                                                         business_id shippingpoint taxzone_id reqdate_unset_or_old insertdatefrom insertdateto
                                                         order_probability_op order_probability_value expected_billing_date_from expected_billing_date_to
-                                                        parts_partnumber parts_description all department_id intnotes);
+                                                        parts_partnumber parts_description all department_id intnotes phone_notes fulltext);
   push @hidden_variables, map { "cvar_$_->{name}" } @ct_searchable_custom_variables;
 
   my   @keys_for_url = grep { $form->{$_} } @hidden_variables;
@@ -1169,6 +1188,8 @@ sub orders {
   push @options, $locale->text('Shipping Point')          . " : $form->{shippingpoint}"                   if $form->{shippingpoint};
   push @options, $locale->text('Part Description')        . " : $form->{parts_description}"               if $form->{parts_description};
   push @options, $locale->text('Part Number')             . " : $form->{parts_partnumber}"                if $form->{parts_partnumber};
+  push @options, $locale->text('Phone Notes')             . " : $form->{phone_notes}"                     if $form->{phone_notes};
+  push @options, $locale->text('Full Text')               . " : $form->{fulltext}"                        if $form->{fulltext};
   if ( $form->{transdatefrom} or $form->{transdateto} ) {
     push @options, $locale->text('Order Date');
     push @options, $locale->text('From') . " " . $locale->date(\%myconfig, $form->{transdatefrom}, 1)     if $form->{transdatefrom};
@@ -1378,6 +1399,8 @@ sub save_and_close {
     IS->get_customer(\%myconfig, $form) if $vc eq 'customer';
     IR->get_vendor(\%myconfig, $form)   if $vc eq 'vendor';
 
+    $::form->{billing_address_id} = $::form->{default_billing_address_id};
+
     update();
     $::dispatcher->end_request;
   }
@@ -1480,8 +1503,13 @@ sub save {
   if (($form->{"previous_${vc}_id"} || $form->{"${vc}_id"}) != $form->{"${vc}_id"}) {
     $::form->{salesman_id} = SL::DB::Manager::Employee->current->id if exists $::form->{salesman_id};
 
-    IS->get_customer(\%myconfig, $form) if $vc eq 'customer';
-    IR->get_vendor(\%myconfig, $form)   if $vc eq 'vendor';
+    if ($vc eq 'customer') {
+      IS->get_customer(\%myconfig, $form);
+      $::form->{billing_address_id} = $::form->{default_billing_address_id};
+
+    } else {
+      IR->get_vendor(\%myconfig, $form);
+    }
 
     update();
     $::dispatcher->end_request;
@@ -1637,7 +1665,7 @@ sub invoice {
     $::dispatcher->end_request;
   }
 
-  _oe_remove_delivered_or_billed_rows(id => $form->{id}, type => 'billed');
+  _oe_remove_delivered_or_billed_rows(id => $form->{id}, type => 'billed') if $form->{new_invoice_type} ne 'final_invoice';
 
   $form->{cp_id} *= 1;
 
@@ -1682,7 +1710,9 @@ sub invoice {
 
   if (   $form->{type} eq 'sales_order'
       || $form->{type} eq 'sales_quotation') {
-    $form->{title}  = $locale->text('Add Sales Invoice');
+    $form->{title}  = ($form->{new_invoice_type} eq 'invoice_for_advance_payment') ? $locale->text('Add Invoice for Advance Payment')
+                    : ($form->{new_invoice_type} eq 'final_invoice')               ? $locale->text('Add Final Invoice')
+                    : $locale->text('Add Sales Invoice');
     $form->{script} = 'is.pl';
     $script         = "is";
     $buysell        = 'buy';
@@ -1691,7 +1721,7 @@ sub invoice {
   # bo creates the id, reset it
   map { delete $form->{$_} } qw(id subject message cc bcc printed emailed queued);
   $form->{ $form->{vc} } =~ s/--.*//g;
-  $form->{type} = "invoice";
+  $form->{type} = $form->{new_invoice_type} || "invoice";
 
   # locale messages
   $main::locale = Locale->new("$myconfig{countrycode}", "$script");
index f6db5e2..630a2b5 100644 (file)
@@ -98,6 +98,7 @@ use strict;
 # $locale->text('Payments')
 # $locale->text('Project Transactions')
 # $locale->text('Business evaluation')
+# $locale->text('Final Invoice, please use mark as paid manually')
 
 # $form->parse_html_template('rp/html_report_susa')
 
@@ -630,7 +631,7 @@ sub generate_trial_balance {
   my $attachment_basename = $locale->text('trial_balance');
   my $report              = SL::ReportGenerator->new(\%myconfig, $form);
 
-  my @hidden_variables    = qw(fromdate todate year method department_id);
+  my @hidden_variables    = qw(fromdate todate year method department_id all_accounts);
 
   my $href                = build_std_url('action=generate_trial_balance', grep { $form->{$_} } @hidden_variables);
 
@@ -1006,8 +1007,7 @@ sub aging {
 
   my $report = SL::ReportGenerator->new(\%myconfig, $form);
 
-  my @columns = qw(statement ct invnumber transdate duedate amount open);
-
+  my @columns = qw(statement ct invnumber transdate duedate amount open datepaid current_open type);
   my %column_defs = (
     'statement' => { raw_header_data => SL::Presenter::Tag::checkbox_tag("checkall", checkall => '[name^=statement_]'), 'visible' => $form->{ct} eq 'customer' ? 'HTML' : 0, align => "center" },
     'ct'        => { 'text' => $form->{ct} eq 'customer' ? $locale->text('Customer') : $locale->text('Vendor'), },
@@ -1016,10 +1016,13 @@ sub aging {
     'duedate'   => { 'text' => $locale->text('Due'), },
     'amount'    => { 'text' => $locale->text('Amount'), },
     'open'      => { 'text' => $locale->text('Open'), },
+    'datepaid'  => { 'text' => $locale->text('Date of Last Payment'), visible => ($form->{reporttype} eq 'custom') },
+    'current_open' => { 'text' => $locale->text('Open Amount at Last Payment Date'), visible => ($form->{reporttype} eq 'custom') },
+    'type'      => { 'text' => $locale->text('Note'), },
   );
 
   my %column_alignment = ('statement' => 'center',
-                          map { $_ => 'right' } qw(open amount));
+                          map { $_ => 'right' } qw(open amount current_open datepaid));
 
   $report->set_options('std_column_visibility' => 1);
   $report->set_columns(%column_defs);
@@ -1048,10 +1051,20 @@ sub aging {
     $form->{title} = sprintf($locale->text('Ap aging on %s'), $form->{todate});
   }
 
-  if ($form->{fromdate}) {
-    push @options, $locale->text('for Period') . " " . $locale->text('From') . " " .$locale->date(\%myconfig, $form->{fromdate}, 1) . " " . $locale->text('Bis') . " " . $locale->date(\%myconfig, $form->{todate}, 1);
+  $form->{callback} .= "&reporttype=" . E($form->{reporttype});
+  if ($form->{reporttype} eq 'free') {
+    if ($form->{fromdate}) {
+      push @options, $locale->text('for Period') . " " . $locale->text('From') . " " .
+      $locale->date(\%myconfig, $form->{fromdate}, 1) . " "                          .
+      $locale->text('Bis') . " " . $locale->date(\%myconfig, $form->{todate}, 1);
+    } else {
+      push @options, $locale->text('for Period') . " " . $locale->text('Bis') . " " .
+      $locale->date(\%myconfig, $form->{todate}, 1);
+    }
+  } elsif ($form->{reporttype} eq 'custom') {
+    push @options, $locale->text('Reference day') . " " . $locale->date(\%myconfig, $form->{fordate}, 1);
   } else {
-    push @options, $locale->text('for Period') . " " . $locale->text('Bis') . " " . $locale->date(\%myconfig, $form->{todate}, 1);
+    die "Unknown reporttype for aging";
   }
 
   $attachment_basename = $form->{ct} eq 'customer' ? $locale->text('ar_aging_list') : $locale->text('ap_aging_list');
@@ -1066,7 +1079,7 @@ sub aging {
 
   my $previous_ctid = 0;
   my $row_idx       = 0;
-  my @periods       = qw(open amount);
+  my @periods       = qw(open amount current_open);
   my %subtotals     = map { $_ => 0 } @periods;
   my %totals        = map { $_ => 0 } @periods;
 
@@ -1092,6 +1105,12 @@ sub aging {
     }
 
     $row->{invnumber}->{link} =  build_std_url("script=$ref->{module}.pl", 'action=edit', 'callback', 'id=' . E($ref->{id}));
+    if ($row->{type}->{data} eq 'final_invoice') {
+      $row->{type}->{data} = $locale->text('Final Invoice, please use mark as paid manually');
+      $row->{type}->{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'callback', 'id=' . E($ref->{id}));
+    } else {
+      $row->{type}->{data} = '';
+    }
 
     if ($previous_ctid != $ref->{ctid}) {
       $row->{statement}->{raw_data} =
index b7750f2..3cb1243 100644 (file)
@@ -198,9 +198,8 @@ sub transfer_or_removal_prepare_contents {
   my $all_units = AM->retrieve_units(\%myconfig, $form);
 
   foreach (@contents) {
-    $_->{qty} = $form->format_amount_units('amount'     => $_->{qty},
-                                           'part_unit'  => $_->{partunit},
-                                           'conv_units' => 'convertible');
+    $_->{qty} = $form->format_amount(\%myconfig, $_->{qty}) . ' ' . $_->{partunit};
+
     my $this_unit = $_->{partunit};
 
     if ($all_units->{$_->{partunit}} && ($all_units->{g}->{base_unit} eq $all_units->{$_->{partunit}}->{base_unit})) {
@@ -574,6 +573,12 @@ sub journal {
 
   show_no_warehouses_error() if (!scalar @{ $form->{WAREHOUSES} });
 
+  my $cvar_configs                           = CVar->get_configs('module' => 'IC');
+  ($form->{CUSTOM_VARIABLES_FILTER_CODE},
+   $form->{CUSTOM_VARIABLES_INCLUSION_CODE}) = CVar->render_search_options('variables'      => $cvar_configs,
+                                                                           'include_prefix' => 'l_',
+                                                                           'include_value'  => 'Y');
+
   setup_wh_journal_action_bar();
 
   $form->header();
@@ -641,9 +646,18 @@ sub generate_journal {
 
   my $report = SL::ReportGenerator->new(\%myconfig, $form);
 
+  my $cvar_configs                 = CVar->get_configs('module' => 'IC');
+  my @includeable_custom_variables = grep { $_->{includeable} } @{ $cvar_configs };
+  my @searchable_custom_variables  = grep { $_->{searchable} }  @{ $cvar_configs };
+  push @columns, map { "cvar_$_->{name}" } @includeable_custom_variables;
+
   my @hidden_variables = map { "l_${_}" } @columns;
   push @hidden_variables, qw(warehouse_id bin_id partnumber description chargenumber bestbefore qty_op qty qty_unit unit partunit fromdate todate transtype_ids comment projectnumber);
   push @hidden_variables, qw(classification_id);
+  push @hidden_variables, map({'cvar_'. $_->{name}}                                         @searchable_custom_variables);
+  push @hidden_variables, map({'cvar_'. $_->{name} .'_from'}  grep({$_->{type} eq  'date'}  @searchable_custom_variables));
+  push @hidden_variables, map({'cvar_'. $_->{name} .'_to'}    grep({$_->{type} eq  'date'}  @searchable_custom_variables));
+  push @hidden_variables, map({'cvar_'. $_->{name} .'_qtyop'} grep({$_->{type} eq 'number'} @searchable_custom_variables));
 
   my %column_defs = (
     'ids'             => { raw_header_data => checkbox_tag("", id => "check_all", checkall  => "[data-checkall=1]") },
@@ -669,6 +683,9 @@ sub generate_journal {
     'oe_id'           => { 'text' => $locale->text('Document'), },
   );
 
+  my %column_defs_cvars = map { +"cvar_$_->{name}" => { 'text' => $_->{description} } } @includeable_custom_variables;
+  %column_defs          = (%column_defs, %column_defs_cvars);
+
   if ($form->{transtype_ids} && 'ARRAY' eq ref $form->{transtype_ids}) {
     for (my $i = 0; $i < scalar(@{ $form->{transtype_ids} }); $i++) {
       delete $form->{transtype_ids}[$i] if $form->{transtype_ids}[$i] eq '';
@@ -679,7 +696,7 @@ sub generate_journal {
   my $href = build_std_url('action=generate_journal', grep { $form->{$_} } @hidden_variables);
   $href .= "&maxrows=".$form->{maxrows};
 
-  map { $column_defs{$_}->{link} = $href ."&page=".$page. "&sort=${_}&order=" . Q($_ eq $form->{sort} ? 1 - $form->{order} : $form->{order}) } @columns;
+  map { $column_defs{$_}->{link} = $href ."&page=".$page. "&sort=${_}&order=" . Q($_ eq $form->{sort} ? 1 - $form->{order} : $form->{order}) } grep {!/^cvar/} @columns;
 
   my %column_alignment = map { $_ => 'right' } qw(qty);
 
@@ -704,6 +721,13 @@ sub generate_journal {
 
   my $all_units = AM->retrieve_units(\%myconfig, $form);
 
+  CVar->add_custom_variables_to_report('module'         => 'IC',
+                                       'trans_id_field' => 'parts_id',
+                                       'configs'        => $cvar_configs,
+                                       'column_defs'    => \%column_defs,
+                                       'data'           => \@contents);
+
+
   my %doc_types = ( 'sales_quotation'         => { script => 'oe', title => $locale->text('Sales quotation') },
                     'sales_order'             => { script => 'oe', title => $locale->text('Sales Order') },
                     'request_quotation'       => { script => 'oe', title => $locale->text('Request quotation') },
@@ -786,12 +810,16 @@ sub report {
   my $locale   = $main::locale;
 
   $form->get_lists('warehouses' => { 'key'    => 'WAREHOUSES',
-                                     'bins'   => 'BINS', });
+                                     'bins'   => 'BINS', },
+                   'partsgroup' => 'PARTSGROUPS');
 
   show_no_warehouses_error() if (!scalar @{ $form->{WAREHOUSES} });
 
-  my $CVAR_CONFIGS = SL::DB::Manager::CustomVariableConfig->get_all_sorted(where => [ module => 'IC' ]);
-  my $INCLUDABLE_CVAR_CONFIGS = [ grep { $_->includeable } @{ $CVAR_CONFIGS } ];
+  my $cvar_configs                           = CVar->get_configs('module' => 'IC');
+  ($form->{CUSTOM_VARIABLES_FILTER_CODE},
+   $form->{CUSTOM_VARIABLES_INCLUSION_CODE}) = CVar->render_search_options('variables'      => $cvar_configs,
+                                                                           'include_prefix' => 'l_',
+                                                                           'include_value'  => 'Y');
 
   $form->{title}   = $locale->text("Report about warehouse contents");
 
@@ -799,10 +827,9 @@ sub report {
 
   $form->header();
   print $form->parse_html_template("wh/report_filter",
-                                   { "WAREHOUSES" => $form->{WAREHOUSES},
-                                     "UNITS"      => AM->unit_select_data(AM->retrieve_units(\%myconfig, $form)),
-                                     # "CVAR_CONFIGS"            => $CVAR_CONFIGS, # nyi searchable cvars
-                                     "INCLUDABLE_CVAR_CONFIGS" => $INCLUDABLE_CVAR_CONFIGS,
+                                   { "WAREHOUSES"  => $form->{WAREHOUSES},
+                                     "PARTSGROUPS" => $form->{PARTSGROUPS},
+                                     "UNITS"       => AM->unit_select_data(AM->retrieve_units(\%myconfig, $form)),
                                    });
 
   $main::lxdebug->leave_sub();
@@ -817,8 +844,6 @@ sub generate_report {
   my %myconfig = %main::myconfig;
   my $locale   = $main::locale;
 
-  my $cvar_configs = CVar->get_configs('module' => 'IC');
-
   $form->{title}   = $locale->text("Report about warehouse contents");
   $form->{sort}  ||= 'partnumber';
   my $sort_col     = $form->{sort};
@@ -827,7 +852,7 @@ sub generate_report {
   my @columns = qw(warehousedescription bindescription partnumber type_and_classific partdescription chargenumber bestbefore comment qty partunit list_price purchase_price stock_value);
 
   # filter stuff
-  map { $filter{$_} = $form->{$_} if ($form->{$_}) } qw(warehouse_id bin_id classification_id partnumber description chargenumber bestbefore date include_invalid_warehouses);
+  map { $filter{$_} = $form->{$_} if ($form->{$_}) } qw(warehouse_id bin_id classification_id partnumber description partsgroup_id chargenumber bestbefore date include_invalid_warehouses);
 
   # show filter stuff also in report
   my @options;
@@ -844,6 +869,8 @@ sub generate_report {
    classification_id => sub { push @options, $locale->text('Parts Classification'). " : ".
                                                SL::DB::Manager::PartClassification->get_first(where => [ id => $form->{classification_id} ] )->description; },
    description    => sub { push @options, $locale->text('Description')    . " : $form->{description}"},
+   partsgroup_id  => sub { push @options, $locale->text('Partsgroup')     . " : " .
+                                            SL::DB::PartsGroup->new(id => $form->{partsgroup_id})->load->partsgroup},
    chargenumber   => sub { push @options, $locale->text('Charge Number')  . " : $form->{chargenumber}"},
    bestbefore     => sub { push @options, $locale->text('Best Before')    . " : $form->{bestbefore}"},
    include_invalid_warehouses    => sub { push @options, $locale->text('Include invalid warehouses ')},
@@ -894,13 +921,19 @@ sub generate_report {
 
   my $report = SL::ReportGenerator->new(\%myconfig, $form);
 
+  my $cvar_configs                 = CVar->get_configs('module' => 'IC');
   my @includeable_custom_variables = grep { $_->{includeable} } @{ $cvar_configs };
+  my @searchable_custom_variables  = grep { $_->{searchable} }  @{ $cvar_configs };
   push @columns, map { "cvar_$_->{name}" } @includeable_custom_variables;
 
   my @hidden_variables = map { "l_${_}" } @columns;
-  push @hidden_variables, qw(warehouse_id bin_id partnumber partstypes_id description chargenumber bestbefore qty_op qty qty_unit partunit l_warehousedescription l_bindescription);
+  push @hidden_variables, qw(warehouse_id bin_id partnumber partstypes_id description partsgroup_id chargenumber bestbefore qty_op qty qty_unit partunit l_warehousedescription l_bindescription);
   push @hidden_variables, qw(include_empty_bins subtotal include_invalid_warehouses date);
   push @hidden_variables, qw(classification_id stock_value_basis allrows);
+  push @hidden_variables, map({'cvar_'. $_->{name}}                                         @searchable_custom_variables);
+  push @hidden_variables, map({'cvar_'. $_->{name} .'_from'}  grep({$_->{type} eq 'date'}   @searchable_custom_variables));
+  push @hidden_variables, map({'cvar_'. $_->{name} .'_to'}    grep({$_->{type} eq 'date'}   @searchable_custom_variables));
+  push @hidden_variables, map({'cvar_'. $_->{name} .'_qtyop'} grep({$_->{type} eq 'number'} @searchable_custom_variables));
 
   my %column_defs = (
     'warehousedescription' => { 'text' => $locale->text('Warehouse'), },
@@ -917,12 +950,13 @@ sub generate_report {
     'list_price'           => { 'text' => $locale->text('List Price'), },
   );
 
+  my %column_defs_cvars = map { +"cvar_$_->{name}" => { 'text' => $_->{description} } } @includeable_custom_variables;
+  %column_defs = (%column_defs, %column_defs_cvars);
+
   my $href = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
   $href .= "&maxrows=".$form->{maxrows};
-  my %column_defs_cvars            = map { +"cvar_$_->{name}" => { 'text' => $_->{description} } } @includeable_custom_variables;
-  %column_defs = (%column_defs, %column_defs_cvars);
 
-  map { $column_defs{$_}->{link} = $href . "&page=".$page."&sort=${_}&order=" . Q($_ eq $sort_col ? 1 - $form->{order} : $form->{order}) } @columns;
+  map { $column_defs{$_}->{link} = $href . "&page=".$page."&sort=${_}&order=" . Q($_ eq $sort_col ? 1 - $form->{order} : $form->{order}) } grep {!/^cvar_/} @columns;
 
   my %column_alignment = map { $_ => 'right' } qw(qty list_price purchase_price stock_value);
 
@@ -966,9 +1000,6 @@ sub generate_report {
     map { $subtotals{$_} += $entry->{$_} } @subtotals_columns;
     $total_stock_value   += $entry->{stock_value} * 1;
     $entry->{qty}         = $form->format_amount(\%myconfig, $entry->{qty});
-#    $entry->{qty}         = $form->format_amount_units('amount'     => $entry->{qty},
-#                                                       'part_unit'  => $entry->{partunit},
-#                                                       'conv_units' => 'convertible');
     $entry->{stock_value} = $form->format_amount(\%myconfig, $entry->{stock_value} * 1, 2);
     $entry->{purchase_price} = $form->format_amount(\%myconfig, $entry->{purchase_price} * 1, 2);
     $entry->{list_price}     = $form->format_amount(\%myconfig, $entry->{list_price}     * 1, 2);
@@ -981,9 +1012,6 @@ sub generate_report {
 
       my $row = { map { $_ => { 'data' => '', 'class' => 'listsubtotal', 'align' => $column_alignment{$_}, } } @columns };
       $row->{qty}->{data}         = $form->format_amount(\%myconfig, $subtotals{qty});
-#      $row->{qty}->{data}         = $form->format_amount_units('amount'     => $subtotals{qty} * 1,
-#                                                               'part_unit'  => $entry->{partunit},
-#                                                               'conv_units' => 'convertible');
       $row->{stock_value}->{data} = $form->format_amount(\%myconfig, $subtotals{stock_value} * 1, 2);
       $row->{purchase_price}->{data} = $form->format_amount(\%myconfig, $subtotals{purchase_price} * 1, 2);
       $row->{list_price}->{data}     = $form->format_amount(\%myconfig, $subtotals{list_price}     * 1, 2);
diff --git a/build/kivitendo-mebil.co b/build/kivitendo-mebil.co
new file mode 100755 (executable)
index 0000000..da0def4
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+set -e
+
+./kivitendo.co $*
+
diff --git a/build/kivitendo-steckbrief.co b/build/kivitendo-steckbrief.co
new file mode 100755 (executable)
index 0000000..c53d61c
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash
+set -e
+
+# parameter: $1: git tag to build
+
+if [ "$1" == "TOP" ]; then
+       mkdir kivitendo-erp/
+       ln -s ../../../doc/ kivitendo-erp/
+       ln -s ../../../image/ kivitendo-erp/
+else
+       ../kivitendo.co $*
+fi
+
+if [ -d GF ]
+then
+       pushd GF >/dev/null
+               svn up
+       popd >/dev/null
+else
+       svn co https://wagnertech.de/svn/verwaltung/GF
+fi
+
+pushd .. >/dev/null
+       ln -sf src/kivitendo-erp/doc/Steckbrief.tex .
+       ln -sf src/GF/wagner_tech_briefbogen_blau_fs1.pdf .
+       ln -sf projects/tools/tex/wallpaper.sty .
+       ln -sf src/kivitendo-erp/image/Bildschirmfoto-kivitendo-steigmann-3.3.0-MozillaFirefox.png Bildschirmfoto.png
+       echo "COMPILE_TARGET = Steckbrief.pdf" >make.pre
+popd >/dev/null
diff --git a/build/kivitendo.co b/build/kivitendo.co
new file mode 100755 (executable)
index 0000000..d3d0f47
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+set -e
+
+# parameter: $1: git tag to build
+# options: -g <alternative repository>
+
+#repos="https://github.com/wagner-tech"
+#if getopts "g:" opt; then
+#      repos=$OPTARG
+#      shift 2
+#fi
+#
+#if [ -e kivitendo-erp ]
+#then
+#      pushd kivitendo-erp >/dev/null
+       #branch=$(git rev-parse --abbrev-ref HEAD)
+       #git pull origin $branch
+#else
+#      git clone $repos/kivitendo-erp
+#      pushd kivitendo-erp >/dev/null
+#fi
+#      git checkout $1
+#popd >/dev/null
+
+# alternativer Versuch: Es wird das lokale Repository geklont:
+
+cwd=$(pwd)
+git clone ${cwd%/build/src}
+pushd kivitendo-erp >/dev/null
+       git checkout $1
+popd >/dev/null
+
diff --git a/build/start-build b/build/start-build
new file mode 100755 (executable)
index 0000000..23256ac
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/bash
+set -e
+
+# checkout build utilities
+if [ -d projects ]; then
+       pushd projects >/dev/null
+               git pull origin master
+       popd >/dev/null
+else
+       git clone https://github.com/wagner-tech/projects/
+fi
+
+ln -sf projects/tools/make/configure .
+
+echo "Next step: call 'configure <project> <tag>'"
+echo "Available are:"
+ls *.co
index 861b6cc..d84e814 100644 (file)
@@ -1,4 +1,4 @@
-kivitendo-erp (3.5.8.1-%BUILD%) unstable; urgency=medium
+kivitendo-erp (0.1-%BUILD%) unstable; urgency=medium
   * start of mebil mapping
  -- Michael Wagner <info@wagnertech.de>  Tue, 08 Feb 2022 20:03:04 +0100
 
index c5b25cc..4b2e27d 100644 (file)
@@ -8,23 +8,6 @@ Package: mkivitendo
 Section: main
 Priority: optional
 Architecture: all
-Depends: apache2, postgresql, libapache2-mod-fcgid, libarchive-zip-perl, libclone-perl,
-  libconfig-std-perl, libdatetime-perl, libdbd-pg-perl, libdbi-perl,
-  libemail-address-perl,  libemail-mime-perl, libfcgi-perl, libjson-perl,
-  liblist-moreutils-perl, libnet-smtp-ssl-perl, libnet-sslglue-perl,
-  libparams-validate-perl, libpdf-api2-perl, librose-db-object-perl,
-  librose-db-perl, librose-object-perl, libsort-naturally-perl,
-  libstring-shellquote-perl, libtemplate-perl, libtext-csv-xs-perl,
-  libtext-iconv-perl, liburi-perl, libxml-writer-perl, libyaml-perl,
-  libimage-info-perl, libgd-gd2-perl,
-  libfile-copy-recursive-perl, libalgorithm-checkdigits-perl,
-  libcrypt-pbkdf2-perl, libcgi-pm-perl, libtext-unidecode-perl, libwww-perl,
-  postgresql-contrib, aqbanking-tools, poppler-utils, libhtml-restrict-perl,
-  libdatetime-set-perl, libset-infinite-perl, liblist-utilsby-perl,
-  libdaemon-generic-perl, libfile-flock-perl, libfile-slurp-perl,
-  libfile-mimeinfo-perl, libpbkdf2-tiny-perl, libregexp-ipv6-perl,
-  libdatetime-event-cron-perl, libexception-class-perl,
-  libcam-pdf-perl, libmath-round-perl
-Replaces: kivitendo
+Depends: kivitendo
 Description: kivitendo-ERP
 
index 907a480..7ee781c 100755 (executable)
@@ -3,21 +3,14 @@ set -e
 
 # parameter: $1: base dir for copy (optional)
 
-mkdir -p $1/opt/kivitendo-erp
-rsync -a --exclude=".git" --exclude="debian" ./ $1/opt/kivitendo-erp/
+. debian/setenv.sh
+mkdir -p $1/opt/mkivitendo
 
-# provide WTG default config file
-cp Downloads/projects/kivitendo/kivitendo.conf.default $1/opt/kivitendo-erp/config/
-
-# postinst
-cp Downloads/projects/debian/kivitendo.postinst debian/tmp/DEBIAN/postinst
-
-# copyright
-cp doc/copyright debian/
-
-# apache files
-mkdir -p $1/etc/apache2/sites-available
-mkdir -p $1/etc/apache2/sites-enabled
-cp Downloads/projects/kivitendo/kivitendo.conf $1/etc/apache2/sites-available
-cd $1/etc/apache2/sites-enabled && ln -sf ../sites-available/kivitendo.conf .
+git diff --stat release-3.6.1 | grep -v debian |grep -v "files changed"| grep -v ".dummy" |sed "s/ //" | sed "s/ .*//" >git.diff
 
+while read line
+do
+       path=${line%.*}
+       mkdir -p $1/opt/mkivitendo/$path
+       cp $line $1/opt/mkivitendo/$path/
+done <git.diff
diff --git a/debian/mkivitendo.postinst b/debian/mkivitendo.postinst
new file mode 100755 (executable)
index 0000000..ecff89e
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+set -ex
+
+rsync -av /opt/mkivitendo/ /opt/kivitendo-erp
+
index f7f4357..4fcc49f 100755 (executable)
@@ -1,16 +1,15 @@
 #!/bin/bash
 set -e
 
-mkdir -p Downloads
-pushd Downloads >/dev/null
+# bestimme Versionsnummer aus VERSION
+base_version=$(cat VERSION)
 
-if [ -d projects ]
-then
-       pushd projects >/dev/null
-       git fetch -t
-       popd >/dev/null
-else
-       git clone https://wagnertech.de/git/projects
-fi
+# Hänge Version aus changelog an
+vline=$(head -1 debian/$paket.changelog)
+vline=${vline%-*}
+cl_version=${vline#*(}
 
+echo "version=$base_version.$cl_version" >> debian/rules.pre
+echo "version=$base_version.$cl_version" >> debian/setenv.sh
+echo "base_version=$base_version" >> debian/setenv.sh
 
diff --git a/doc/Steckbrief.tex b/doc/Steckbrief.tex
new file mode 100644 (file)
index 0000000..95b04ce
--- /dev/null
@@ -0,0 +1,54 @@
+\documentclass{scrartcl}
+\usepackage[utf8]{inputenc}% muss zum Editor passen -> http://texwelt.de/wissen/fragen/2656/
+\usepackage[T1]{fontenc}
+\usepackage[ngerman]{babel}
+\usepackage{multicol}
+\usepackage{wallpaper}
+\usepackage{hyperref} 
+
+\usepackage{geometry}
+\geometry{a4paper,left=25mm,right=25mm, top=25mm, bottom=3cm}
+
+\renewcommand{\familydefault}{\sfdefault}
+
+\title{kivitendo: Ein Programm für Buchhaltung und Lagerwesen}
+\author{WagnerTech UG, Turfstr. 18a, 81929 München, www.wagnertech.de}
+\date{\vspace{-5ex}}
+
+\ULCornerWallPaper{1}{wagner_tech_briefbogen_blau_fs1.pdf}
+
+\begin{document}
+
+\pagenumbering{gobble} % no page numbers
+\maketitle
+
+\begin{abstract}
+kivitendo zur Buchhaltung: kivitendo ist ein browserbasiertes Buchhaltungsprogramm, mehrbenutzer- und mandantenfähig (\url{http://www.kivitendo.org}). kivitendo-mebil sind Ergänzungen der WagnerTech UG, darunter eine Finanzamtsschnittstelle zur Übertragung
+der monatlichen UStVA.
+
+\end{abstract}
+
+\begin{multicols}{2}
+Im Bereich der OpenSource-Software gibt es heute viele Programme, die für die geschäftlichen Anforderungen kleiner und mittelgroßer Unternehmen geeignet sind. Der Vorteil von quelloffener Software liegt dabei nicht primär in der kostenlosen Verfügbarkeit, sondern darin, dass sie von jedermann, also auch von uns, für Ihre speziellen Bedürfnisse angepasst werden dürfen.
+
+Das Programm kivitendo ist eine vielseitige, ausgereifte Anwendung, die kleinen und mittelgroßen Firmen
+die für die Buchhaltung und das Lagerwesen nötigen Funktionen zur Verfügung stellt. kivitendo ist „das Eine“ für „das Alles“: Basis-ERP-System mit Artikeln, Waren, Kunden, Lieferanten, Lager, Angeboten, Rechnungen, Mahnwesen, Buchungsvorbereitung für die Fibu, Kontakte mit grundlegenden CRM-Funktionen und noch einiges mehr.
+
+kivitendo wird auf einem Server betrieben. Die Mitarbeiter greifen über ihren Webbrowser auf das Programm zu. Eine lokale
+Installation entfällt damit.
+Für die Zusammenarbeit mit Ihrem Steuerberater bietet kivitendo einen DATEV-Export.
+
+WagnerTech UG betreut Sie bei Installation und Einführung und kann das Programm auch nach Ihren speziellen Anforderungen
+ergänzen. Eine erste Ergänzung, die wir kivitendo hinzugefügt haben, ist eine Finanzamtsschnittstelle zur Übertragung der
+monatlichen Umsatzsteueranmeldung.
+\end{multicols}
+
+\begin{figure} [h]
+   \centering
+      \frame{\includegraphics[width=0.8 \linewidth]{Bildschirmfoto.png}}
+   %\captionof{figure}{Aussehen einer Lohnabrechnung}
+   \label{abb:screenshot}
+\end{figure}
+
+
+\end{document}
index ffc055c..6b809ee 100644 (file)
@@ -3,6 +3,37 @@ Wichtige Hinweise zum Upgrade von älteren Versionen
 
 ** BITTE FERTIGEN SIE VOR DEM UPGRADE EIN BACKUP IHRER DATENBANK(EN) AN! **
 
+Upgrade auf v3.6.1
+
+Das manueller Korrigieren der Steuer bei Skontoverbuchungen entfällt seit
+dieser Version, da die Steuerkorrektur automatisch gemacht wird.
+
+Ein neues Perl-Modul ist hinzugekommen, Hilfe zum Installieren bietet wie immer
+das Skript 'scripts/installation_check.pl -v'.
+
+  * IPC::Run
+
+
+Upgrade auf v3.6.0
+
+Der 'neue Auftrags-Controller' ist mittlerweile weder neu noch experimentell und
+die entsprechende Mandantenkonfiguration 'Experimentellen neuen Auftrags-Controller'
+verwenden wird bei diesem Upgrade hart auf 'Ja' gesetzt.
+Die alte, noch aktive Auftragsmaske wird in einer zukünftigen Version von kivitendo entfernt
+werden.
+
+Einige neue Perl-Module sind hinzugekommen, Hilfe zum Installieren bietet wie immer
+das Skript 'scripts/installation_check.pl -v'.
+
+  * Neue Perl Abhängigkeiten:
+
+  * Term::ReadLine::Gnu
+  * Imager::QRCode
+  * Imager
+  * REST::Client
+
+
+
 Upgrade auf v3.5.8
 
 Die API für 'Erzeugnis fertigen' wurde geändert:
index f83a5ca..88a0e01 100644 (file)
@@ -2,6 +2,212 @@
 # Veränderungen von kivitendo #
 ###############################
 
+2022-05-20 - Release 3.6.1
+
+Größere neue Features:
+
+Mittelgroße neue Features:
+
+ - Neuer Workflow Artikel->Lieferantenaufrag. Hierbei wird der gerade
+   bearbeitete Artikel gespeichert und die Lieferantenauftrags-Maske
+   geöffnet. Der Artikel ist dann in der Eingabezeile vorbelegt.
+   Sofern genau ein Lieferant beim Artikel hinterlegt ist, so wird
+   auch dieser im Lieferantenauftrag vorbelegt.
+ - In Angebot und Auftrag gibt es einen neuen Reiter für Telefonnotizen.
+   Hier können Notizen zum Beleg erfasst werden. Nach diesen lässt sich im
+   Bericht auch filtern.
+ - Neuer Filter im Auftragsbericht nach "Volltext". Hierzu werden die Texte in
+   den Feldern Bemerkungen, interne Bemerkungen, Versandort, Transportmittel,
+   Vorgangsbezeichnung, Auftragsnummer, Angebotsnummer und
+   Bestellnummer des Kunden durchsucht,
+   Zudem werden Dokumente und Anhänge zu Aufträgen im DMS durchsucht.
+   Dazu wird ein Hintgergrund-Job eingerichtet (täglich 03:20 Uhr), der die
+   Texte aus den Dokumenten extrahiert. Im Moment werden Texte aus Dokumenten
+   mit den mime-Typen 'application/pdf', 'text/html' und 'text/plain'
+   ausgelesen.
+
+Kleinere neue Features und Detailverbesserungen:
+
+ - Die Protokollierung von E-Mails in interne Bemerkungen ist deaktiviert,
+   falls der Mandant sowieso das E-Mail-Journal aktiviert hat.
+ - Steuerschlüssel 94, 19 und 18 neu angelegt und um Reverse Charge erweitert.
+   D.h. bei diesen Steuerschlüsseln
+   kann in einem netto verbuchten Kreditorenbeleg gleichzeitig Vor- und
+   Mehrwertsteuer verbucht werden. Die Steuerbuchung wird in einer separat
+   verknüpften Dialogbuchung gemacht.
+ - Im Kunden-/Lieferantenbereicht kann nach "allen Telefonnummern" gefiltert
+   werden. Hier wird in den Feldern Telefon und Fax bei Kunden und Lieferanten
+   und in weiteren Feldern bei Ansprechpersonen (Tel. 1/2, Fax, Mobil 1/2,
+   Sat. Tel, Sat. Fax, Privates Tel.) gesucht.
+ - Es gibt eine neue Schnellsuche "Alle Telefonnummern", die alle Telefonnumern
+   bei Kunden, Lieferanten und Ansprechpersonen durchsucht.
+-  Skontoautomatik bei Kontoauszug verbuchen generiert automatisch die
+   Steuerkorrektur pro Steuersatz des Belegs als verknüpfte Dialogbuchung
+-  Verknüpfte Belege auch für Dialogbuchungen (neuer Reiter)
+-  DMS: Anzeige von Versionen verbessert: Angezeigt wird immer nur die neueste
+   Version einer Datei. Weitere Versionen lassen sich durch Ausklappen
+   anzeigen. Dies gilt nun auch für die Dokument-Typen Anhänge und Bilder, bei
+   denen zuvor nur die neueste Version angezeigt wurde.
+-  Um ein ungewolltes doppeltes Buchen einer Verkaufsrechnung zu verhindern,
+   dass durch den Browser-Zurück-Knopf (und dann nochmaliges Buchen) ausgelöst
+   werden kann, kann in der Mandantenkonfiguration das Aushebeln des Browser-
+   Zurück-Knopfes bei Verkaufsrechnunghen aktiviert werden.
+   Da dadurch allerdings auch Situationen ausgehebelt werden, in denen das
+   Drücken des Zurück-Knopfes sinnvoll ist, ist dies konfigurierbar.
+-  Rechte (nur) zum Lesen von Belegen, getrennt nach Einkauf/Verkauf und
+   Angebot/Auftrag/Lieferschein/Rechnung. Wer nur das Lese-Recht hat, kann
+   Belege nicht anlegen und nicht speichern.
+-  neues Feld "Vorgangsbezeichnung" in Kreditoren-, Debitoren und Dialogbuchung.
+-  Rechnungsbericht VK und EK kann nach Steuerzone gefiltert und sortieren werden.
+-  Möglichkeit, Namen von Dateianhängen im Rechnungsbericht anzuzeigen.
+
+
+Bugfixes (Tracker: https://www.kivitendo.de/redmine):
+
+498 Angebot/Auftrags-Maske: Drucken mit nicht-änderbarer Belegnummer zeigt diese nicht an
+494 Beim Erstellen eines Auftrags via Workflow aus der Kundenmaske wird die Sprache nicht übernommen
+491 qty real nach numeric migrieren
+479 Preise neuer Auftragsconroller
+
+
+2022-03-02 - Release 3.6.0
+
+Größere neue Features:
+
+- Mobilvariante Handyfotos für Lieferscheine
+
+  Die neue mobile Variante von kivitendo kann Handyfotos an Lieferscheine hinzufügen.
+  Das Feature setzt ein mobiles Endgerät voraus, aufgrund dessen wird ein passendes
+  CSS-Design im Android-Stil geladen und über die Suche nach einem Lieferschein lassen
+  sich aufgenommen Fotos hochladen. Die Funktion benötigt ein aktiviertes DMS innerhalb
+  von kivitendo.
+
+- Lieferanten-Beistelllieferschein
+
+  Über den Lieferantenworkflow ist es jetzt möglich
+  einen Lieferantenausgangslieferschein zu erstellen (beigestellte Ware).
+  Mit diesem neuen Belegtyp können dann für einen Lieferanten Waren ausgelagert,
+  sprich mitgegeben werden. Damit kann der Anwendungsfall: Lieferant veredelt
+  eigene Erzeugnisse weiter oder erbringt Dienstleistungen mit selbst erzeugter
+  Ware abgebildet werden.
+  Dieser Belegtyp wurde vollständig unabhängig vom alten Lieferschein-Code ent-
+  wickelt (MVC Modell, wie beim neueren Auftrag) und enthält die Option
+  Belegart (Einkauf oder Verkauf) sowie Lagerrichtung (Ein- oder Auslagern) beliebig
+  zu kombinieren.
+
+- Shopware 6 Schnittstelle
+
+  kivitendo unterstützt jetzt die neuere Shopware Version 6 als Alternative
+  zum bisherigen Shopware 5 Konnektor. Die meisten Funktionen sind analog zum
+  Shopware 5 Konnektor implementiert. Admins können sich im Detail im Perl-Doc
+  über die Implementierung informieren (perldoc SL/ShopConnector/Shopware6.pm).
+
+- Anzahlungs- und Schlussrechnung konform nach deutschem Steuerrecht
+
+  Es gibt zwei neue Typen von Rechnungen, einmal den Typ Anzahlungsrechnung und den Typ Schlußrechnung.
+  Die Anzahlungsrechnung braucht keinen Vorgänger.
+  Schlußrechnung braucht immer einen Vorgänger.
+  Vorgänger für die Schlußrechnung kann eine Anzahlungsrechnung oder ein Auftrag sein.
+  Sollte der Workflow bei Anzahlungsrechnung starten, kann von der Anzahlungsrechnung aus eine
+  weitere Anzahlungsrechnung oder eine Schlußrechnung generiert werden.
+  Alternativ kann der Workflow auch mit einem Auftrag beginnen, dann muss die Schlußrechnung auch von diesem Auftrag aus erstellt werden.
+  Buchhalterische Änderungen:
+  Die Anzahlungsrechnung wird nicht auf das Standard-Ertragkonto gebucht,
+  sondern auf ein definiertes Transferkonto, ferner wird keine Mehrwertsteuer gebucht.
+  Sobald der Zahlungseingang zu dieser Anzahlungsrechnung verbucht wird (per Bankimport),
+  wird die Mehrwertsteuer entsprechend zum Zahlbetrag brutto verbucht.
+  Damit das ganze DATEV konform bleibt, wird der entsprechende netto Betrag des Zahlbetrags
+  auf ein Steuertransferkonto je nach Steuersatz verschoben.
+  Sobald die Schlußrechnung gebucht wird, werden die Verschiebungen wieder rückgängig gemacht
+  und falls die Schlußrechnung in Summe höher ist als die vorherigen Anzahlungsrechnungen wird
+  die Mehrwertsteuer anteilig gebucht.
+  Die Standard-Druckvorlage marei, enthält exemplarisch zwei neue Druckvarianten die
+  diesen Fall abbilden und somit als Orientierung für eigene Vorlagen-Anpassungen
+  dienen können.
+
+
+Mittelgroße neue Features:
+
+- In Kundenstammdaten können nun abweichende Rechnungsadressen analog zu
+  Lieferadressen verwaltet werden. Diese können in Verkaufsbelegen
+  ausgewählt werden. Sie stehen den Druckvorlagen als eigene Variablen
+  zur Verfügung.
+- Unterstützung für Schweizer QR-Rechnung mit OpenDocument Vorlagen.
+  Varianten: QR-IBAN mit QR-Referenz, IBAN ohne Referenz
+- Neuer benutzerdefinierter Variablentyp HTML-Feld
+  Der Funktionsumfang entspricht dem Editor im Langtext/Bemerkungen
+  innerhalb der Belege. Erweiterbar für alle auch bisher verwendete
+  Objekte die benutzerdefinierte Variable verwenden können (Stammdaten,
+  Projekte, usw)
+- DMS unterstützt auch Druckvarianten des Belegs
+  Bisher konnte das DMS nur die Hauptvariante des Belegtyps zuordnen,
+  jetzt wird auch bei allen bekannten Druckvariante ein entsprechend
+  eigenständiger Dokumenteneintrag, inkl. Version hinterlegt
+
+Kleinere neue Features und Detailverbesserungen:
+
+- neue Druckvorlagen-Variante "Rechnungskopie", die mit dem Druckvorlagensatz marei
+  ein Wasserzeichen "Rechnungskopie" bei Verkaufs-Rechnungen erzeugt
+- Alle HTML-Textfelder benutzen die Rechtschreibprüfung des Anwender-Browser und
+  markieren unbekannte Worte (Tippfehler) mit einer roten gewellten Linie
+- Prüfung, ob Kundenbestellnummer in Verkaufsaufträgen vorhanden ist, kann in der
+  Mandantenkonfiguration eingestellt werden
+- Optionale Warnung falls eine Verkaufsrechnung nicht aus einem Lieferschein
+  erzeugt wurde (Konfigurierbar in der Mandantenkonfiguration)
+- Die Ansicht der verknüpften Belegen kann unabhängig vom aktuellen Beleg immer
+  vom Auftrag her aufgebaut werden
+- SEPA-Überweisungen & -Bankeinzüge nutzen jetzt aktuelle Standard-Versionen, die
+  momentan von der Kreditindustrie unterstützt werden.
+- Pflichtenhefte: wenn man im Workflow vom Pflichtenheft ein neues
+  Angebot anlegt und später von diesem Angebot aus einen Auftrag, so
+  wird auch der Auftrag direkt mit dem Pflichtenheft verknüpft.
+- Pflichtenhefte: wenn in einem Auftrag, das mit einem Pflichtenheft
+  verknüpft ist, ein Projekt ausgewählt, so wird dieses Projekt auch
+  automatisch beim verknüpften Pflichtenheft eingetragen.
+- Druckvorlagen: die in Positionen verwendeten Variablen können nun
+  Platzhalter enthalten, die vom Beleg selber stammen. So könnte
+  z.B. in der Artikelbeschreibung automatisch die Rechnungsnummer
+  ersetzt werden. Beispiel: »Abrechnungszeitraum bis <%invnumber%>«
+- Verkaufs- & Einkaufsbelege: kivitendo kann so konfiguriert werden,
+  dass die Belegnummern von Belegen, die auf unserer Seite erzeugt
+  werden, nicht mehr editierbar sind. In dem Fall vergibt kivitendo
+  sie immer automatisch und zeigt sie in den Belegmasken nur noch an.
+- Warengruppe kann nun als Pflichtfeld für Artikel konfiguriert werden.
+- Das E-Mail Feld 'body' innerhalb von kivitendo unterstützt jetzt HTML-Formatierungen
+  Somit kann der Versand von wiederkehrenden Rechnungen als auch der
+  manuelle E-Mail-Versand von Belegen wie das Beleg-Bemerkungsfeld formatiert werden.
+- Für die HTML-Texte ist jetzt die Rechtschreibprüfung des Anwender-Browsers aktiviert
+- Beim E-Mail-Versand wird jetzt gewarnt, falls scheinbar keine
+  gültige E-Mail-Adresse des Empfängers existiert
+- Optionale auftragszentrische Verknüpfte Belege
+  Konfigurierbar in der Mandantenkonfiguration. Unabhängig vom
+  aktuellen Belegort werden die verknüpften Belege immer vom VK-Auftrag aufgebaut.
+- Lieferplan: Geschwindigkeitssteigerung
+- SEPA: aktuell von Kreditinstituten unterstützte Formatversionen nutzen
+- Pflichtenhefte: bei Pflichtenheft → Angebot → Auftrag auch PH mit Auftrag verknüpfen
+- Auftrag: Projekt automatisch in verknüpftem Pflichtenheft eintragen
+- Ein-/Verkauf: Belegnummern von uns erzeugter Belege nicht ändern können (Mandantenkonfig)
+  Für Belege, die auf unserer Seite erzeugt werden, kann nun verhindert
+  werden, dass die Belegnummer manuell angepasst bzw. gesetzt
+  wird. Statt dessen wird sie immer vom System beim ersten Speichern
+  vergeben und beim späteren Bearbeiten nur noch read-only angezeigt.
+- Verkaufsrechnungen direkt als Factur-X/ZUGFeRD-XML exportieren können
+- Order-Controller: Unterstützung für Drucken & E-Mailen von HTML-Vorlage
+- Der Lagerbewegungs-Import (CSV) unterstützt auch Fließkommazahlen
+- E-Mails aus kivitendo werden jetzt HTML-formatiert verschickt, mit
+  den bekannten Editiermöglichkeiten aus den Bemerkungen/Langtext
+- Bei längeren Langtexten in der Position ist jetzt ein Vergrößern des
+  Textfelds im Popup-Dialog möglich
+
+
+Bugfixes (Tracker: https://www.kivitendo.de/redmine):
+
+488 Lager ohne Lagerplatz nicht erlauben
+486 Bericht Lagerentnahme: Link zur Ware kaputt
+485 Offenen Forderungen zum Stichtag mit aktuellem Status
+484 CSV/PDF-Export Summen- und Saldenliste mit allen Konten
+
+
 2021-08-10 - Release 3.5.8
 
 Kleinere neue Features und Detailverbesserungen:
index 014bd63..1da2798 100644 (file)
@@ -2,7 +2,7 @@
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <book id="kivitendo-documentation" lang="de">
-  <title>kivitendo 3.5.8: Installation, Konfiguration,
+  <title>kivitendo 3.6.1: Installation, Konfiguration,
   Entwicklung</title>
 
   <chapter id="Aktuelle-Hinweise">
             <para><literal>Image::Info</literal></para>
           </listitem>
 
+          <listitem>
+            <para><literal>Imager</literal></para>
+          </listitem>
+
+          <listitem>
+            <para><literal>Imager::QRCode</literal></para>
+          </listitem>
+
+          <listitem>
+            <para><literal>IPC::Run</literal></para>
+          </listitem>
+
           <listitem>
             <para><literal>JSON</literal></para>
           </listitem>
             <para><literal>Regexp::IPv6</literal></para>
           </listitem>
 
+          <listitem>
+            <para><literal>Rest::Client</literal></para>
+          </listitem>
+
           <listitem>
             <para><literal>Rose::Object</literal></para>
           </listitem>
         </itemizedlist>
 
 
+        <para>Seit Version größer v3.6.0 sind die folgenden Pakete hinzugekommen: <literal>IPC::Run</literal></para>
+
+        <para>Seit Version größer v3.5.8 sind die folgenden Pakete hinzugekommen: <literal>Imager</literal>, <literal>Imager::QRCode</literal>
+<literal>Rest::Client</literal><literal>Term::ReadLine::Gnu</literal></para>
+
         <para>Seit Version größer v3.5.6 sind die folgenden Pakete hinzugekommen: <literal>Try::Tiny</literal>, <literal>Math::Round</literal></para>
         <para>Seit Version größer v3.5.6 sind die folgenden Pakete hinzugekommen: <literal>XML::LibXML</literal>, <literal>CAM::PDF</literal></para>
         <para>Seit Version größer v3.5.3 sind die folgenden Pakete hinzugekommen: <literal>Exception::Class</literal></para>
   libtext-iconv-perl liburi-perl libxml-writer-perl libyaml-perl \
   libimage-info-perl libgd-gd2-perl libapache2-mod-fcgid \
   libfile-copy-recursive-perl postgresql libalgorithm-checkdigits-perl \
-  libcrypt-pbkdf2-perl git libcgi-pm-perl libtext-unidecode-perl libwww-perl\
-  postgresql-contrib poppler-utils libhtml-restrict-perl\
-  libdatetime-set-perl libset-infinite-perl liblist-utilsby-perl\
-  libdaemon-generic-perl libfile-flock-perl libfile-slurp-perl\
+  libcrypt-pbkdf2-perl git libcgi-pm-perl libtext-unidecode-perl libwww-perl \
+  postgresql-contrib poppler-utils libhtml-restrict-perl \
+  libdatetime-set-perl libset-infinite-perl liblist-utilsby-perl \
+  libdaemon-generic-perl libfile-flock-perl libfile-slurp-perl \
   libfile-mimeinfo-perl libpbkdf2-tiny-perl libregexp-ipv6-perl \
   libdatetime-event-cron-perl libexception-class-perl libcam-pdf-perl \
-  libxml-libxml-perl libtry-tiny-perl libmath-round-perl
-</programlisting>
-<para>Sollten Pakete nicht zu Verfügung stehen, so können diese auch mittels CPAN installiert werden. Ferner muss für Ubuntu das Repository "Universe" aktiv sein (s.a. Anmerkungen).</para>
+  libxml-libxml-perl libtry-tiny-perl libmath-round-perl \
+  libimager-perl libimager-qrcode-perl librest-client-perl libipc-run-perl
+          </programlisting>
+
+          <para>Sollten Pakete nicht zu Verfügung stehen, so können diese auch mittels CPAN installiert werden. Ferner muss für Ubuntu das Repository "Universe" aktiv sein (s.a. Anmerkungen).</para>
           <note id="ubuntu-universe">
             <para>Die Perl Pakete für Ubuntu befinden sich im "Universe" Repository. Falls dies nicht aktiv ist, kann dies mit folgendem Aufruf aktiviert werden:
 <programlisting>add-apt-repository universe</programlisting></para>
@@ -1319,7 +1342,7 @@ Alias       /url/for/kivitendo-erp-fcgid/          /path/to/kivitendo-erp/</prog
         url="https://mozilla.github.io/server-side-tls/ssl-config-generator/">
         SSL-Konfigurations-Generator</ulink>.</para>
       </sect2>
-      <sect3>
+      <sect2>
         <title>Aktivierung von Apache2 modsecurity</title>
 
         <para>Aufgrund des OpenSource Charakters ist kivitendo nicht "out of the box" sicher.
@@ -1330,7 +1353,7 @@ XSS und SQL-Injections verhindert werden.</para>
 <para> Als Idee hierfür sei dieser Blog-Eintrag genannt:
 <ulink url="https://doxsec.wordpress.com/2017/06/11/using-modsecurity-web-application-firewall-to-prevent-sql-injection-and-xss-using-blocking-rules/">
         Test Apache2 modsecurity for SQL Injection</ulink>.</para>
-      </sect3>
+      </sect2>
 
     </sect1>
 
@@ -1537,7 +1560,7 @@ systemctl enable kivitendo-task-server.service</programlisting>
           <listitem>
             <para><literal>status</literal> berichtet, ob der Task-Server
             läuft.</para>
-          </listitem>yy
+          </listitem>
         </itemizedlist>
 
         <para>Der Task-Server wechselt beim Starten automatisch in das
@@ -1550,7 +1573,7 @@ systemctl enable kivitendo-task-server.service</programlisting>
         so startet dieser nach Beendigung automatisch erneut.</para>
 
       </sect2>
-      <sect2 id="Tasks konfigurieren">
+      <sect2 id="Tasks-konfigurieren">
         <title>Exemplarische Konfiguration eines Hintergrund-Jobs, der die Jahreszahl in allen Nummernkreisen zum Jahreswechsel erhöht</title>
 
         <para>Hintergrund-Jobs werden über System -> Hintergrund-Jobs und Task-Server -> Aktuelle Hintergrund-Jobs anzeigen -> Aktions-Knopf 'erfassen' angelegt. </para>
@@ -1597,7 +1620,7 @@ multiplier     Nummernkreis 2020
 1000      ->   2020000
 </programlisting>
 <para>Wir gehen jetzt beispielhaft von einer letzten Rechnungsnummer von RE2019456 aus. Demnach sollte ab Januar 2020 die erste Nummer RE2020001 sein. Da der Task auch Präfixe berücksichtigt, kann dies mit folgenden JSON-kodierten Werten umgesetzt werden:</para>
-<literal>Daten:</literal><programlisting>multiplier: 100
+<para><literal>Daten:</literal></para><programlisting>multiplier: 100
 digits_year: 4</programlisting>
           </listitem>
         </itemizedlist>
@@ -2199,7 +2222,7 @@ digits_year: 4</programlisting>
   texlive-collection-latexrecommended texlive-collection-langgerman \
   texlive-collection-langenglish</programlisting></para>
 
-      <note>kivitendo erwartet eine aktuelle TeX Live Umgebung, um PDF/A zu erzeugen. Aktuelle Distributionen von 2020 erfüllen diese. Überprüfbar ist dies mit dem Aufruf des installation_check.pl mit Parameter -l: <programlisting>scripts/installations_check.pl -l</programlisting> </note>
+      <note><para>kivitendo erwartet eine aktuelle TeX Live Umgebung, um PDF/A zu erzeugen. Aktuelle Distributionen von 2020 erfüllen diese. Überprüfbar ist dies mit dem Aufruf des installation_check.pl mit Parameter -l:</para><para><programlisting>scripts/installations_check.pl -l</programlisting></para></note>
       <para>kivitendo bringt drei alternative Vorlagensätze mit:</para>
 
       <itemizedlist>
@@ -2215,7 +2238,7 @@ digits_year: 4</programlisting>
       </itemizedlist>
 
       <para>Der ehemalige Druckvorlagensatz "f-tex" wurde mit der Version
-      3.6 entfernt, da er nicht mehr gepflegt wird.</para>
+      3.5.6 entfernt, da er nicht mehr gepflegt wird.</para>
 
       <sect2 id="Vorlagenverzeichnis-anlegen"
              xreflabel="Vorlagenverzeichnis anlegen">
@@ -2555,7 +2578,7 @@ digits_year: 4</programlisting>
           sales_order_besr.odt</para>
         </sect3>
 
-        <sect3>
+        <sect3 id="opendocument-druckvorlagen-mit-makros.vorbereitungen">
           <title>Vorbereitungen im Adminbereich</title>
 
           <para>Damit beim Erstellen von Rechnungen und Aufträgen neben der
@@ -2768,6 +2791,193 @@ digits_year: 4</programlisting>
           </itemizedlist>
         </sect3>
       </sect2>
+
+      <sect2>
+        <title>Schweizer QR-Rechnung mit OpenDocument Vorlagen</title>
+
+        <sect3>
+          <title>Übersicht</title>
+
+          <para>Mit der Version 3.6.0 unterstützt Kivitendo die Erstellung von
+          Schweizer QR-Rechnungen gemäss <ulink
+          url="https://www.paymentstandards.ch/dam/downloads/ig-qr-bill-de.pdf">Swiss
+          Payment Standards, Version 2.2</ulink>. Implementiert sind hierbei die
+          Varianten:</para>
+
+          <itemizedlist>
+            <listitem>
+              <para><emphasis role="bold">QR-IBAN mit
+              QR-Referenz</emphasis></para>
+            </listitem>
+
+            <listitem>
+              <para><emphasis role="bold">IBAN ohne Referenz</emphasis></para>
+            </listitem>
+          </itemizedlist>
+
+          <para>Der Vorlagensatz "rev-odt" enthält die Vorlage
+          <literal>invoice_qr.odt</literal>, welche für die Erstellung von
+          QR-Rechnungen vorgesehen ist. Damit diese verwendet werden kann muss
+          wie obenstehend beschrieben ein Drucker hinzugefügt werden (siehe
+          <xref linkend="opendocument-druckvorlagen-mit-makros.vorbereitungen"/>
+          ). Alternativ kann die Vorlage umbenannt werden in
+          <literal>invoice.odt</literal>.</para>
+
+          <para>Die Vorlage <literal>invoice_qr.odt</literal> kann beliebig
+          angepasst werden. Zwingend muss diese jedoch das QR-Code Platzhalter
+          Bild, als eingebettetes Bild, enthalten. Da dieses beim
+          Ausdrucken/Erzeugen der Rechnung durch das neu generierte QR-Code
+          Bild ersetzt wird.</para>
+        </sect3>
+
+        <sect3>
+          <title>Einstellungen</title>
+
+          <sect4>
+            <title>Mandantenkonfiguration</title>
+
+            <para>Unter <emphasis>System → Mandantenkonfiguration →
+            Features</emphasis>. Im Abschnitt <emphasis>Einkauf und
+            Verkauf</emphasis>, beim Punkt <emphasis>Verkaufsrechnungen mit
+            Schweizer QR-Rechnung erzeugen</emphasis>, die gewünschte Variante
+            wählen.</para>
+          </sect4>
+
+          <sect4>
+            <title>Konfiguration der Bankkonten</title>
+
+            <para>Unter <emphasis>System → Bankkonten</emphasis> muss bei
+            mindestens einem Bankkonto die Option <emphasis>Nutzung mit
+            Schweizer QR-Rechnung</emphasis> auf <emphasis
+            role="bold">Ja</emphasis> gestellt werden.</para>
+
+            <tip>
+              <para>Für die Variante <emphasis role="bold">QR-IBAN mit
+              QR-Referenz</emphasis> muss dieses Konto unter IBAN eine gültige
+              <emphasis role="bold">QR-IBAN Nummer</emphasis> enthalten. Diese
+              unterscheidet sich von der regulären IBAN.</para>
+
+              <para>Zusätzlich muss eine gültige <emphasis role="bold">Bankkonto
+              Identifikationsnummer</emphasis> angegeben werden
+              (6-stellig).</para>
+
+              <para>Diese werden von der jeweiligen Bank vergeben.</para>
+            </tip>
+
+            <para>Sind mehrere Konten ausgewählt wird das erste
+            verwendet.</para>
+          </sect4>
+
+          <sect4>
+            <title>Rechnungen ohne Betrag</title>
+
+            <para>Für Rechnungen ohne Betrag (z.B. Spenden) kann, in der
+            jeweiligen Rechnung, die Checkbox <emphasis>QR-Rechnung ohne
+            Betrag</emphasis> aktiviert werden. Diese Checkbox erscheint nur,
+            wenn QR-Rechnungen in der Mandantenkonfiguration aktiviert sind
+            (variante ausgewählt).</para>
+
+            <para>Dies wirkt sich lediglich auf den erzeugten QR-Code aus. Die
+            Vorlage muss separat angepasst und ausgewählt werden.</para>
+          </sect4>
+        </sect3>
+
+        <sect3>
+          <title>Adressdaten</title>
+
+          <para>Die Adressdaten zum Zahlungsempfänger werden aus der
+          Mandantenkonfiguration entnommen. Unter <emphasis>System →
+          Mandantenkonfiguration → Verschiedenes</emphasis>, Abschnitt
+          <emphasis>Firmenname und -adresse.</emphasis></para>
+
+          <para>Die Adressdaten zum Zahlungspflichtigen stammen aus den
+          Kundendaten der jeweiligen Rechnung.</para>
+
+          <para>Die Adressen müssen inklusive Land angegeben werden. Akzeptiert
+          werden Ländername oder Ländercode, also z.B. "Schweiz" oder "CH".
+          </para>
+
+          <para>Diese können in der Vorlage mit den jeweiligen Variablen
+          eingetragen werden. Siehe auch: <xref
+          linkend="dokumentenvorlagen-und-variablen"/></para>
+
+          <para>Der erzeugte QR-Code verwendet Adress-Typ "K" (Kombinierte
+          Adressfelder, 2 Zeilen).</para>
+        </sect3>
+
+        <sect3>
+          <title>Referenznummer</title>
+
+          <para>Die Referenznummer wird in Kivitendo erzeugt und setzt sich
+          wiefolgt zusammen:</para>
+
+          <itemizedlist>
+            <listitem>
+              <para>Bankkonto Identifikationsnummer (6-stellig)</para>
+            </listitem>
+
+            <listitem>
+              <para>Kundennummer (6-stellig, mit führenden Nullen
+              aufgefüllt)</para>
+            </listitem>
+
+            <listitem>
+              <para>Auftragsnummer (7-stellig, mit führenden Nullen
+              aufgefüllt)</para>
+            </listitem>
+
+            <listitem>
+              <para>Rechnungsnummer (7-stellig, mit führenden Nullen
+              aufgefüllt)</para>
+            </listitem>
+
+            <listitem>
+              <para>Prüfziffer (1-stellig, berechnet mittels modulo 10,
+              rekursiv)</para>
+            </listitem>
+          </itemizedlist>
+
+          <para>Es sind lediglich Ziffern erlaubt. Allfällige Prefixe mit
+          Buchstaben werden entfernt und fehlende Stellen werden mit führenden
+          Nullen aufgefüllt.</para>
+        </sect3>
+
+        <sect3>
+          <title>Zusätzliche Variablen für Vorlage</title>
+
+          <para>Zusätzlich zu den in der Vorlage standardmässig verfügbaren
+          Variablen (siehe <xref linkend="dokumentenvorlagen-und-variablen"/>),
+          werden die folgenden Variablen erzeugt:</para>
+
+          <variablelist>
+            <varlistentry>
+              <term>ref_number_formatted</term>
+
+              <listitem>
+                <para>Referenznummer formatiert mit Leerzeichen, z.B.: 21 00000
+                00003 13947 14300 09017</para>
+              </listitem>
+            </varlistentry>
+
+            <varlistentry>
+              <term>iban_formatted</term>
+
+              <listitem>
+                <para>IBAN formatiert mit Leerzeichen</para>
+              </listitem>
+            </varlistentry>
+
+            <varlistentry>
+              <term>amount_formatted</term>
+
+              <listitem>
+                <para>Betrag formatiert mit Tausendertrennzeichen Leerschlag,
+                z.B.: 1 005.55</para>
+              </listitem>
+            </varlistentry>
+          </variablelist>
+        </sect3>
+      </sect2>
     </sect1>
 
     <sect1 id="nomenclature">
@@ -4895,6 +5105,32 @@ digits_year: 4</programlisting>
             </varlistentry>
           </variablelist>
         </sect3>
+
+        <sect3 id="dokumentenvorlagen-und-variablen.abweichende-rechnungsadresse">
+          <title>Informationen über abweichende Rechnungsadressen (nur Verkaufsbelege)</title>
+
+          <para>
+            Abweichende Rechnungsadressen gibt es nur in Verkaufsbelegen. Die entsprechenden Variablen sind nur dann mit Inhalt gefüllt,
+            wenn im Beleg eine abweichende Rechnungsadresse ausgewählt wurde. Ob eine Adresse überhaupt ausgewählt wurde, kann über die
+            Variable <literal>billing_address_id</literal> getestet werden, die die Datenbank-ID der abweichenden Rechnungsadresse enthält,
+            wenn eine ausgewählt ist.
+          </para>
+
+          <para>
+            Die Variablennamen starten alle mit dem Präfix <literal>billing_address_</literal> und heißen anschließend so, wie ihre Pendants
+            aus der Standard-Rechnungsadresse des Kunden. Beispiel: die Postleitzahl, die in der normalen Rechnungsadresse in
+            <literal>zipcode</literal> steht, steht für die abweichende Rechnungsadresse in <literal>billing_address_zipcode</literal>.
+          </para>
+
+          <para>
+            Die folgenden Variablen stehen so zur Verfügung: <literal>billing_address_name</literal>,
+            <literal>billing_address_department_1</literal>, <literal>billing_address_department_2</literal>,
+            <literal>billing_address_contact</literal>, <literal>billing_address_street</literal>,
+            <literal>billing_address_zipcode</literal>, <literal>billing_address_city</literal>, <literal>billing_address_country</literal>,
+            <literal>billing_address_gln</literal>, <literal>billing_address_email</literal>, <literal>billing_address_phone</literal> und
+            <literal>billing_address_fax</literal>.
+          </para>
+        </sect3>
       </sect2>
 
       <sect2 id="dokumentenvorlagen-und-variablen.invoice">
@@ -7189,7 +7425,7 @@ document_path = /var/local/kivi_documents
                        Version 3.5.6 den ZUGFeRD 2.1 Standard um.</para>
 
                        <para>Weiter Details zu ZUGFeRD sind unter diesem Link zu finden:
-                       <ulink>https://www.ferd-net.de/standards/was-ist-zugferd/index.html</ulink>
+                       <ulink url="https://www.ferd-net.de/standards/was-ist-zugferd/index.html">https://www.ferd-net.de/standards/was-ist-zugferd/index.html</ulink>
       </para>
                </sect2>
 
index cbe7cea..1e8bca3 100644 (file)
@@ -1,9 +1,9 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>Kapitel 1. Aktuelle Hinweise</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="prev" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="next" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 1. Aktuelle Hinweise</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 1. Aktuelle Hinweise"><div class="titlepage"><div><div><h2 class="title"><a name="Aktuelle-Hinweise"></a>Kapitel 1. Aktuelle Hinweise</h2></div></div></div><p>Aktuelle Installations- und Konfigurationshinweise gibt es:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>im Community-Forum: <a class="ulink" href="https://forum.kivitendo.de" target="_top">https://forum.kivitendo.de</a>
+   <title>Kapitel 1. Aktuelle Hinweise</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="prev" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="next" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 1. Aktuelle Hinweise</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 1. Aktuelle Hinweise"><div class="titlepage"><div><div><h2 class="title"><a name="Aktuelle-Hinweise"></a>Kapitel 1. Aktuelle Hinweise</h2></div></div></div><p>Aktuelle Installations- und Konfigurationshinweise gibt es:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>im Community-Forum: <a class="ulink" href="https://forum.kivitendo.de" target="_top">https://forum.kivitendo.de</a>
             </p></li><li class="listitem"><p>im Kunden-Forum: <a class="ulink" href="http://redmine.kivitendo-premium.de/projects/forum/boards/" target="_top">http://redmine.kivitendo-premium.de/projects/forum/boards/</a>
             </p></li><li class="listitem"><p>in der doc/UPGRADE Datei im doc-Verzeichnis der
         Installation</p></li><li class="listitem"><p>Im Schulungs- und Dienstleistungsangebot der entsprechenden
         kivitendo-Partner: <a class="ulink" href="http://www.kivitendo.de/partner.html" target="_top">http://www.kivitendo.de/partner.html</a>
-            </p></li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html">Zurück</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">kivitendo 3.5.8: Installation, Konfiguration,
+            </p></li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html">Zurück</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">kivitendo 3.6.1: Installation, Konfiguration,
   Entwicklung&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Zum Anfang</a></td><td width="40%" align="right" valign="top">&nbsp;Kapitel 2. Installation und Grundkonfiguration</td></tr></table></div></body></html>
\ No newline at end of file
index 49392fe..1c494b7 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>Kapitel 2. Installation und Grundkonfiguration</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="prev" href="ch01.html" title="Kapitel 1. Aktuelle Hinweise"><link rel="next" href="ch02s02.html" title="2.2. Benötigte Software und Pakete"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 2. Installation und Grundkonfiguration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 2. Installation und Grundkonfiguration"><div class="titlepage"><div><div><h2 class="title"><a name="config"></a>Kapitel 2. Installation und Grundkonfiguration</h2></div></div></div><div class="sect1" title="2.1. Übersicht"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Installation-%C3%9Cbersicht"></a>2.1. Übersicht</h2></div></div></div><p>Die Installation von kivitendo umfasst mehrere Schritte. Die
+   <title>Kapitel 2. Installation und Grundkonfiguration</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="prev" href="ch01.html" title="Kapitel 1. Aktuelle Hinweise"><link rel="next" href="ch02s02.html" title="2.2. Benötigte Software und Pakete"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 2. Installation und Grundkonfiguration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 2. Installation und Grundkonfiguration"><div class="titlepage"><div><div><h2 class="title"><a name="config"></a>Kapitel 2. Installation und Grundkonfiguration</h2></div></div></div><div class="sect1" title="2.1. Übersicht"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Installation-%C3%9Cbersicht"></a>2.1. Übersicht</h2></div></div></div><p>Die Installation von kivitendo umfasst mehrere Schritte. Die
       folgende Liste kann sowohl für Neulinge als auch für alte Hasen als
       Übersicht und Stichpunktliste zum Abhaken dienen, um eine Version mit
       minimalen Features möglichst schnell zum Laufen zu kriegen.</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
index be8ff0e..1a0ec01 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.2. Benötigte Software und Pakete</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="next" href="ch02s03.html" title="2.3. Manuelle Installation des Programmpaketes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.2. Benötigte Software und Pakete</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s03.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.2. Benötigte Software und Pakete"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Ben%C3%B6tigte-Software-und-Pakete"></a>2.2. Benötigte Software und Pakete</h2></div></div></div><div class="sect2" title="2.2.1. Betriebssystem"><div class="titlepage"><div><div><h3 class="title"><a name="Betriebssystem"></a>2.2.1. Betriebssystem</h3></div></div></div><p>kivitendo ist für Linux konzipiert, und sollte auf jedem
+   <title>2.2. Benötigte Software und Pakete</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="next" href="ch02s03.html" title="2.3. Manuelle Installation des Programmpaketes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.2. Benötigte Software und Pakete</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s03.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.2. Benötigte Software und Pakete"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Ben%C3%B6tigte-Software-und-Pakete"></a>2.2. Benötigte Software und Pakete</h2></div></div></div><div class="sect2" title="2.2.1. Betriebssystem"><div class="titlepage"><div><div><h3 class="title"><a name="Betriebssystem"></a>2.2.1. Betriebssystem</h3></div></div></div><p>kivitendo ist für Linux konzipiert, und sollte auf jedem
         unixoiden Betriebssystem zum Laufen zu kriegen sein. Getestet ist
         diese Version im speziellen auf Debian und Ubuntu, grundsätzlich wurde
         bei der Auswahl der Pakete aber darauf Rücksicht genommen, dass es
                      <code class="literal">HTML::Restrict</code>
                   </p></li><li class="listitem"><p>
                      <code class="literal">Image::Info</code>
+                  </p></li><li class="listitem"><p>
+                     <code class="literal">Imager</code>
+                  </p></li><li class="listitem"><p>
+                     <code class="literal">Imager::QRCode</code>
+                  </p></li><li class="listitem"><p>
+                     <code class="literal">IPC::Run</code>
                   </p></li><li class="listitem"><p>
                      <code class="literal">JSON</code>
                   </p></li><li class="listitem"><p>
@@ -84,6 +90,8 @@
                      <code class="literal">PDF::API2</code>
                   </p></li><li class="listitem"><p>
                      <code class="literal">Regexp::IPv6</code>
+                  </p></li><li class="listitem"><p>
+                     <code class="literal">Rest::Client</code>
                   </p></li><li class="listitem"><p>
                      <code class="literal">Rose::Object</code>
                   </p></li><li class="listitem"><p>
                      <code class="literal">XML::LibXML</code>
                   </p></li><li class="listitem"><p>
                      <code class="literal">YAML::XS</code> oder <code class="literal">YAML</code>
-                  </p></li></ul></div><p>Seit Version größer v3.5.6 sind die folgenden Pakete hinzugekommen: <code class="literal">Try::Tiny</code>, <code class="literal">Math::Round</code>
+                  </p></li></ul></div><p>Seit Version größer v3.6.0 sind die folgenden Pakete hinzugekommen: <code class="literal">IPC::Run</code>
+            </p><p>Seit Version größer v3.5.8 sind die folgenden Pakete hinzugekommen: <code class="literal">Imager</code>, <code class="literal">Imager::QRCode</code>
+
+               <code class="literal">Rest::Client</code>
+               <code class="literal">Term::ReadLine::Gnu</code>
+            </p><p>Seit Version größer v3.5.6 sind die folgenden Pakete hinzugekommen: <code class="literal">Try::Tiny</code>, <code class="literal">Math::Round</code>
             </p><p>Seit Version größer v3.5.6 sind die folgenden Pakete hinzugekommen: <code class="literal">XML::LibXML</code>, <code class="literal">CAM::PDF</code>
             </p><p>Seit Version größer v3.5.3 sind die folgenden Pakete hinzugekommen: <code class="literal">Exception::Class</code>
             </p><p>Seit Version größer v3.5.1 sind die folgenden Pakete hinzugekommen: <code class="literal">Set::Infinite</code>,
         sind auch in 2.6.1 weiterhin mit ausgeliefert, wurden in einer
         zukünftigen Version aber aus dem Paket entfernt werden. Es wird
         empfohlen diese Module zusammen mit den anderen als Bibliotheken zu
-        installieren.</p><div class="sect3" title="2.2.2.1. Debian und Ubuntu"><div class="titlepage"><div><div><h4 class="title"><a name="d0e591"></a>2.2.2.1. Debian und Ubuntu</h4></div></div></div><p>Für Debian und Ubuntu stehen die meisten der benötigten
+        installieren.</p><div class="sect3" title="2.2.2.1. Debian und Ubuntu"><div class="titlepage"><div><div><h4 class="title"><a name="d0e634"></a>2.2.2.1. Debian und Ubuntu</h4></div></div></div><p>Für Debian und Ubuntu stehen die meisten der benötigten
           Pakete als Debian-Pakete zur Verfügung. Sie können mit
           folgendem Befehl installiert werden:</p><pre class="programlisting">apt install  apache2 libarchive-zip-perl libclone-perl \
   libconfig-std-perl libdatetime-perl libdbd-pg-perl libdbi-perl \
   libtext-iconv-perl liburi-perl libxml-writer-perl libyaml-perl \
   libimage-info-perl libgd-gd2-perl libapache2-mod-fcgid \
   libfile-copy-recursive-perl postgresql libalgorithm-checkdigits-perl \
-  libcrypt-pbkdf2-perl git libcgi-pm-perl libtext-unidecode-perl libwww-perl\
-  postgresql-contrib poppler-utils libhtml-restrict-perl\
-  libdatetime-set-perl libset-infinite-perl liblist-utilsby-perl\
-  libdaemon-generic-perl libfile-flock-perl libfile-slurp-perl\
+  libcrypt-pbkdf2-perl git libcgi-pm-perl libtext-unidecode-perl libwww-perl \
+  postgresql-contrib poppler-utils libhtml-restrict-perl \
+  libdatetime-set-perl libset-infinite-perl liblist-utilsby-perl \
+  libdaemon-generic-perl libfile-flock-perl libfile-slurp-perl \
   libfile-mimeinfo-perl libpbkdf2-tiny-perl libregexp-ipv6-perl \
   libdatetime-event-cron-perl libexception-class-perl libcam-pdf-perl \
-  libxml-libxml-perl libtry-tiny-perl libmath-round-perl
-</pre><p>Sollten Pakete nicht zu Verfügung stehen, so können diese auch mittels CPAN installiert werden. Ferner muss für Ubuntu das Repository "Universe" aktiv sein (s.a. Anmerkungen).</p><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left"><a name="ubuntu-universe"></a>Anmerkung</th></tr><tr><td align="left" valign="top"><p>Die Perl Pakete für Ubuntu befinden sich im "Universe" Repository. Falls dies nicht aktiv ist, kann dies mit folgendem Aufruf aktiviert werden:
+  libxml-libxml-perl libtry-tiny-perl libmath-round-perl \
+  libimager-perl libimager-qrcode-perl librest-client-perl libipc-run-perl
+          </pre><p>Sollten Pakete nicht zu Verfügung stehen, so können diese auch mittels CPAN installiert werden. Ferner muss für Ubuntu das Repository "Universe" aktiv sein (s.a. Anmerkungen).</p><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left"><a name="ubuntu-universe"></a>Anmerkung</th></tr><tr><td align="left" valign="top"><p>Die Perl Pakete für Ubuntu befinden sich im "Universe" Repository. Falls dies nicht aktiv ist, kann dies mit folgendem Aufruf aktiviert werden:
 </p><pre class="programlisting">add-apt-repository universe</pre><p>
-                  </p></td></tr></table></div></div><div class="sect3" title="2.2.2.2. Fedora"><div class="titlepage"><div><div><h4 class="title"><a name="d0e606"></a>2.2.2.2. Fedora</h4></div></div></div><p>Für Fedora stehen die meisten der benötigten Perl-Pakete als
+                  </p></td></tr></table></div></div><div class="sect3" title="2.2.2.2. Fedora"><div class="titlepage"><div><div><h4 class="title"><a name="d0e649"></a>2.2.2.2. Fedora</h4></div></div></div><p>Für Fedora stehen die meisten der benötigten Perl-Pakete als
           RPM-Pakete zur Verfügung. Sie können mit folgendem Befehl
           installiert werden:</p><pre class="programlisting">dnf install httpd mod_fcgid postgresql-server postgresql-contrib\
   perl-Algorithm-CheckDigits perl-Archive-Zip perl-CPAN perl-Class-XSAccessor \
   perl-Params-Validate perl-Regexp-IPv6 perl-Rose-DB perl-Rose-DB-Object \
   perl-Rose-Object perl-Sort-Naturally perl-String-ShellQuote \
   perl-Template-Toolkit perl-Text-CSV_XS perl-Text-Iconv perl-URI perl-XML-Writer \
-  perl-YAML perl-libwww-perl</pre></div><div class="sect3" title="2.2.2.3. openSUSE Leap 15.x und SUSE Linux Enterprise Server 15 GA"><div class="titlepage"><div><div><h4 class="title"><a name="d0e613"></a>2.2.2.3. openSUSE Leap 15.x und SUSE Linux Enterprise Server 15 GA</h4></div></div></div><p>Für openSUSE Leap 15.x stehen die meisten der benötigten Perl-Pakete als RPM-Pakete zur Verfügung.</p><p>Damit diese installiert werden können, muß das System die erforderlichen Repositories kennen und Zugriff über das Internet darauf haben.</p><p>Daher machen wir die Repositories dem System bekannt.</p><p>Um die zusätzlichen Repositories für die Installation zur Verfügung zu stellen, kann man diese mit YaST oder auch in einem Terminal auf der Konsole bekannt geben. Wir beschränken uns hier mit der Eingabe auf der Konsole. In den allermeisten Fällen verwenden die Administratoren eine sichere SSH-Verbindung zum zu administrierenden Server.</p><p>Dazu geben wir folgenden Befehl ein:</p><pre class="programlisting">zypper addrepo -f \
+  perl-YAML perl-libwww-perl</pre></div><div class="sect3" title="2.2.2.3. openSUSE Leap 15.x und SUSE Linux Enterprise Server 15 GA"><div class="titlepage"><div><div><h4 class="title"><a name="d0e656"></a>2.2.2.3. openSUSE Leap 15.x und SUSE Linux Enterprise Server 15 GA</h4></div></div></div><p>Für openSUSE Leap 15.x stehen die meisten der benötigten Perl-Pakete als RPM-Pakete zur Verfügung.</p><p>Damit diese installiert werden können, muß das System die erforderlichen Repositories kennen und Zugriff über das Internet darauf haben.</p><p>Daher machen wir die Repositories dem System bekannt.</p><p>Um die zusätzlichen Repositories für die Installation zur Verfügung zu stellen, kann man diese mit YaST oder auch in einem Terminal auf der Konsole bekannt geben. Wir beschränken uns hier mit der Eingabe auf der Konsole. In den allermeisten Fällen verwenden die Administratoren eine sichere SSH-Verbindung zum zu administrierenden Server.</p><p>Dazu geben wir folgenden Befehl ein:</p><pre class="programlisting">zypper addrepo -f \
   http://download.opensuse.org/repositories/devel:languages:perl/openSUSE_Leap_15.2/ \
   "devel:languages:perl"
           </pre><pre class="programlisting">zypper addrepo -f \
   texlive-upca
           </pre><p>Zusätzlich müssen einige Pakete aus dem CPAN installiert
           werden. Dazu können Sie die folgenden Befehle anwenden:</p><pre class="programlisting">cpan DateTime::event::Cron DateTime::Set FCGI \
-  HTML::Restrict PBKDF2::Tiny Rose::Db::Object Set::Infinite</pre></div></div><div class="sect2" title="2.2.3. Andere Pakete installieren"><div class="titlepage"><div><div><h3 class="title"><a name="d0e675"></a>2.2.3. Andere Pakete installieren</h3></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
+  HTML::Restrict PBKDF2::Tiny Rose::Db::Object Set::Infinite</pre></div></div><div class="sect2" title="2.2.3. Andere Pakete installieren"><div class="titlepage"><div><div><h3 class="title"><a name="d0e718"></a>2.2.3. Andere Pakete installieren</h3></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                      <code class="literal">poppler-utils</code> 'pdfinfo' zum Erkennen der Seitenanzahl bei der PDF-Generierung</p></li><li class="listitem"><p>
                      <code class="literal">Postgres Trigram-Index</code> Für datenbankoptimierte Suchanfragen. Bspw. im Paket <code class="literal">postgresql-contrib</code> enthalten</p></li></ul></div><p>Debian und Ubuntu: </p><pre class="programlisting">apt install postgresql-contrib poppler-utils</pre><p>
             </p><p>Fedora: </p><pre class="programlisting">dnf install poppler-utils postgresql-contrib</pre><p>
index 92d544b..584a17a 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.3. Manuelle Installation des Programmpaketes</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s02.html" title="2.2. Benötigte Software und Pakete"><link rel="next" href="ch02s04.html" title="2.4. kivitendo-Konfigurationsdatei"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.3. Manuelle Installation des Programmpaketes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s02.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.3. Manuelle Installation des Programmpaketes"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Manuelle-Installation-des-Programmpaketes"></a>2.3. Manuelle Installation des Programmpaketes</h2></div></div></div><p>Der aktuelle Stable-Release, bzw. beta Release wird bei github
+   <title>2.3. Manuelle Installation des Programmpaketes</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s02.html" title="2.2. Benötigte Software und Pakete"><link rel="next" href="ch02s04.html" title="2.4. kivitendo-Konfigurationsdatei"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.3. Manuelle Installation des Programmpaketes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s02.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.3. Manuelle Installation des Programmpaketes"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Manuelle-Installation-des-Programmpaketes"></a>2.3. Manuelle Installation des Programmpaketes</h2></div></div></div><p>Der aktuelle Stable-Release, bzw. beta Release wird bei github
       gehostet und kann <a class="ulink" href="https://github.com/kivitendo/kivitendo-erp/releases" target="_top">hier</a>
       heruntergeladen werden.</p><p>Das aktuelleste kivitendo ERP-Archiv
       (<code class="filename">kivitendo-erp-*.tgz</code>) wird dann im
index c6f6edd..7de19f2 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.4. kivitendo-Konfigurationsdatei</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s03.html" title="2.3. Manuelle Installation des Programmpaketes"><link rel="next" href="ch02s05.html" title="2.5. Anpassung der PostgreSQL-Konfiguration"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.4. kivitendo-Konfigurationsdatei</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s03.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s05.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.4. kivitendo-Konfigurationsdatei"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.config-file"></a>2.4. kivitendo-Konfigurationsdatei</h2></div></div></div><div class="sect2" title="2.4.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="config.config-file.introduction"></a>2.4.1. Einführung</h3></div></div></div><p>In kivitendo gibt es nur noch eine Konfigurationsdatei, die
+   <title>2.4. kivitendo-Konfigurationsdatei</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s03.html" title="2.3. Manuelle Installation des Programmpaketes"><link rel="next" href="ch02s05.html" title="2.5. Anpassung der PostgreSQL-Konfiguration"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.4. kivitendo-Konfigurationsdatei</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s03.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s05.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.4. kivitendo-Konfigurationsdatei"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.config-file"></a>2.4. kivitendo-Konfigurationsdatei</h2></div></div></div><div class="sect2" title="2.4.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="config.config-file.introduction"></a>2.4.1. Einführung</h3></div></div></div><p>In kivitendo gibt es nur noch eine Konfigurationsdatei, die
         benötigt wird: <code class="filename">config/kivitendo.conf</code> (kurz: "die
         Hauptkonfigurationsdatei"). Diese muss bei der Erstinstallation von
         kivitendo bzw. der Migration von älteren Versionen angelegt
index 044ca97..c598c47 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.5. Anpassung der PostgreSQL-Konfiguration</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s04.html" title="2.4. kivitendo-Konfigurationsdatei"><link rel="next" href="ch02s06.html" title="2.6. Webserver-Konfiguration"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.5. Anpassung der PostgreSQL-Konfiguration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s04.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s06.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.5. Anpassung der PostgreSQL-Konfiguration"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Anpassung-der-PostgreSQL-Konfiguration"></a>2.5. Anpassung der PostgreSQL-Konfiguration</h2></div></div></div><p>PostgreSQL muss auf verschiedene Weisen angepasst werden.</p><p>Dies variert je nach eingesetzter Distribution, da distributionsabhängig unterschiedliche Strategien beim Upgrade der Postgres Version eingesetzt werden.
+   <title>2.5. Anpassung der PostgreSQL-Konfiguration</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s04.html" title="2.4. kivitendo-Konfigurationsdatei"><link rel="next" href="ch02s06.html" title="2.6. Webserver-Konfiguration"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.5. Anpassung der PostgreSQL-Konfiguration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s04.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s06.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.5. Anpassung der PostgreSQL-Konfiguration"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Anpassung-der-PostgreSQL-Konfiguration"></a>2.5. Anpassung der PostgreSQL-Konfiguration</h2></div></div></div><p>PostgreSQL muss auf verschiedene Weisen angepasst werden.</p><p>Dies variert je nach eingesetzter Distribution, da distributionsabhängig unterschiedliche Strategien beim Upgrade der Postgres Version eingesetzt werden.
             Als Hinweis einige Links zu den drei Distribution (Stand Dezember 2018):</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                   <a class="ulink" href="https://fedoraproject.org/wiki/PostgreSQL" target="_top">Fedora (Postgres-Installation unter Fedora)</a>
                </p></li><li class="listitem"><p>
index 1e54655..59be848 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.6. Webserver-Konfiguration</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s05.html" title="2.5. Anpassung der PostgreSQL-Konfiguration"><link rel="next" href="ch02s07.html" title="2.7. Der Task-Server"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.6. Webserver-Konfiguration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s05.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s07.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.6. Webserver-Konfiguration"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Apache-Konfiguration"></a>2.6. Webserver-Konfiguration</h2></div></div></div><div class="sect2" title="2.6.1. Grundkonfiguration mittels CGI"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1149"></a>2.6.1. Grundkonfiguration mittels CGI</h3></div></div></div><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left">Anmerkung</th></tr><tr><td align="left" valign="top"><p>Für einen deutlichen Performanceschub sorgt die Ausführung
+   <title>2.6. Webserver-Konfiguration</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s05.html" title="2.5. Anpassung der PostgreSQL-Konfiguration"><link rel="next" href="ch02s07.html" title="2.7. Der Task-Server"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.6. Webserver-Konfiguration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s05.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s07.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.6. Webserver-Konfiguration"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Apache-Konfiguration"></a>2.6. Webserver-Konfiguration</h2></div></div></div><div class="sect2" title="2.6.1. Grundkonfiguration mittels CGI"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1192"></a>2.6.1. Grundkonfiguration mittels CGI</h3></div></div></div><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left">Anmerkung</th></tr><tr><td align="left" valign="top"><p>Für einen deutlichen Performanceschub sorgt die Ausführung
           mittels FastCGI/FCGI. Die Einrichtung wird ausführlich im Abschnitt
           <a class="xref" href="ch02s06.html#Apache-Konfiguration.FCGI" title="2.6.2. Konfiguration für FastCGI/FCGI">Konfiguration für FastCGI/FCGI</a> beschrieben.</p></td></tr></table></div><p>Der Zugriff auf das Programmverzeichnis muss in der Apache
         Webserverkonfigurationsdatei <code class="literal">httpd.conf</code> eingestellt
@@ -104,13 +104,13 @@ AliasMatch ^/url/for/kivitendo-erp-fcgid/[^/]+\.pl /path/to/kivitendo-erp/dispat
 Alias       /url/for/kivitendo-erp-fcgid/          /path/to/kivitendo-erp/</pre><p>Dann ist unter <code class="filename">/url/for/kivitendo-erp/</code>
           die normale Version erreichbar, und unter
           <code class="constant">/url/for/kivitendo-erp-fcgid/</code> die
-          FastCGI-Version.</p></div></div><div class="sect2" title="2.6.3. Authentifizierung mittels HTTP Basic Authentication"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1303"></a>2.6.3. Authentifizierung mittels HTTP Basic Authentication</h3></div></div></div><p>
+          FastCGI-Version.</p></div></div><div class="sect2" title="2.6.3. Authentifizierung mittels HTTP Basic Authentication"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1346"></a>2.6.3. Authentifizierung mittels HTTP Basic Authentication</h3></div></div></div><p>
         Kivitendo unterstützt, dass Benutzerauthentifizierung über den Webserver mittels des »Basic«-HTTP-Authentifizierungs-Schema erfolgt
         (siehe <a class="ulink" href="https://tools.ietf.org/html/rfc7617" target="_top">RFC 7617</a>). Dazu ist es aber nötig, dass der dabei vom Client
         mitgeschickte Header <code class="constant">Authorization</code> vom Webserver an Kivitendo über die Umgebungsvariable
         <code class="constant">HTTP_AUTHORIZATION</code> weitergegeben wird, was standardmäßig nicht der Fall ist. Für Apache kann dies über die
         folgende Konfigurationsoption aktiviert werden:
-       </p><pre class="programlisting">SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1</pre></div><div class="sect2" title="2.6.4. Aktivierung von mod_rewrite/directory_match für git basierte Installationen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1319"></a>2.6.4. Aktivierung von mod_rewrite/directory_match für git basierte Installationen</h3></div></div></div><p>
+       </p><pre class="programlisting">SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1</pre></div><div class="sect2" title="2.6.4. Aktivierung von mod_rewrite/directory_match für git basierte Installationen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1362"></a>2.6.4. Aktivierung von mod_rewrite/directory_match für git basierte Installationen</h3></div></div></div><p>
         Aufgrund von aktuellen (Mitte 2020) Sicherheitswarnungen für git basierte Webanwendungen ist die mitausgelieferte .htaccess
         restriktiver geworden und verhindert somit das Auslesen von git basierten Daten.
         Für debian/ubuntu muss das Modul mod_rewrite einmalig so aktiviert werden:
@@ -125,13 +125,13 @@ Alias       /url/for/kivitendo-erp-fcgid/          /path/to/kivitendo-erp/</pre>
           Require all denied
         &lt;/DirectoryMatch&gt;</pre><p>
        
-            </p></div><div class="sect2" title="2.6.5. Weitergehende Konfiguration"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1333"></a>2.6.5. Weitergehende Konfiguration</h3></div></div></div><p>Für einen deutlichen Sicherheitsmehrwert sorgt die Ausführung
+            </p></div><div class="sect2" title="2.6.5. Weitergehende Konfiguration"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1376"></a>2.6.5. Weitergehende Konfiguration</h3></div></div></div><p>Für einen deutlichen Sicherheitsmehrwert sorgt die Ausführung
         von kivitendo nur über https-verschlüsselten Verbindungen, sowie
         weiteren Zusatzmassnahmen, wie beispielsweise Basic Authenticate. Die
         Konfigurationsmöglichkeiten sprengen allerdings den Rahmen dieser
         Anleitung, hier ein Hinweis auf einen entsprechenden <a class="ulink" href="http://redmine.kivitendo-premium.de/boards/1/topics/142" target="_top">Foreneintrag
         (Stand Sept. 2015)</a> und einen aktuellen (Stand Mai 2017) <a class="ulink" href="https://mozilla.github.io/server-side-tls/ssl-config-generator/" target="_top">
-        SSL-Konfigurations-Generator</a>.</p></div><div class="sect3" title="2.6.1. Aktivierung von Apache2 modsecurity"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1344"></a>2.6.1. Aktivierung von Apache2 modsecurity</h4></div></div></div><p>Aufgrund des OpenSource Charakters ist kivitendo nicht "out of the box" sicher.
+        SSL-Konfigurations-Generator</a>.</p></div><div class="sect2" title="2.6.6. Aktivierung von Apache2 modsecurity"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1387"></a>2.6.6. Aktivierung von Apache2 modsecurity</h3></div></div></div><p>Aufgrund des OpenSource Charakters ist kivitendo nicht "out of the box" sicher.
   Organisatorisch empfehlen wir hier die enge Zusammenarbeit mit einem kivitendo Partner der auch in der
 Lage ist weiterführende Fragen in Bezug auf Datenschutz und Datensicherheit zu beantworten.
 Unabhängig davon empfehlen wir im Webserver Bereich die Aktivierung und Konfiguration des Moduls modsecurity für den Apache2, damit
index 4508495..39312f8 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.7. Der Task-Server</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s06.html" title="2.6. Webserver-Konfiguration"><link rel="next" href="ch02s08.html" title="2.8. Benutzerauthentifizierung und Administratorpasswort"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.7. Der Task-Server</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s06.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s08.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.7. Der Task-Server"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.task-server"></a>2.7. Der Task-Server</h2></div></div></div><p>Der Task-Server ist ein Prozess, der im Hintergrund läuft, in
+   <title>2.7. Der Task-Server</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s06.html" title="2.6. Webserver-Konfiguration"><link rel="next" href="ch02s08.html" title="2.8. Benutzerauthentifizierung und Administratorpasswort"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.7. Der Task-Server</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s06.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s08.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.7. Der Task-Server"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.task-server"></a>2.7. Der Task-Server</h2></div></div></div><p>Der Task-Server ist ein Prozess, der im Hintergrund läuft, in
       regelmäßigen Abständen nach abzuarbeitenden Aufgaben sucht und diese zu
       festgelegten Zeitpunkten abarbeitet (ähnlich wie Cron). Dieser Prozess
       wird u.a. für die Erzeugung der wiederkehrenden Rechnungen und weitere
@@ -44,7 +44,7 @@
         Links aus einem der Runlevel-Verzeichnisse heraus in den Boot-Prozess
         einzubinden. Da das bei neueren Linux-Distributionen aber nicht
         zwangsläufig funktioniert, werden auch Start-Scripte mitgeliefert, die
-        anstelle eines symbolischen Links verwendet werden können.</p><div class="sect3" title="2.7.3.1. SystemV-basierende Systeme (z.B. ältere Debian, ältere openSUSE, ältere Fedora)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1417"></a>2.7.3.1. SystemV-basierende Systeme (z.B. ältere Debian, ältere
+        anstelle eines symbolischen Links verwendet werden können.</p><div class="sect3" title="2.7.3.1. SystemV-basierende Systeme (z.B. ältere Debian, ältere openSUSE, ältere Fedora)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1460"></a>2.7.3.1. SystemV-basierende Systeme (z.B. ältere Debian, ältere
           openSUSE, ältere Fedora)</h4></div></div></div><p>Kopieren Sie die Datei
           <code class="filename">scripts/boot/system-v/kivitendo-task-server</code>
           nach <code class="filename">/etc/init.d/kivitendo-task-server</code>. Passen
           <code class="literal">DAEMON=....</code>). Binden Sie das Script in den
           Boot-Prozess ein. Dies ist distributionsabhängig:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Debian-basierende Systeme:</p><pre class="programlisting">update-rc.d kivitendo-task-server defaults
 insserv kivitendo-task-server</pre></li><li class="listitem"><p>Ältere openSUSE und ältere Fedora:</p><pre class="programlisting">chkconfig --add kivitendo-task-server</pre></li></ul></div><p>Danach kann der Task-Server mit dem folgenden Befehl gestartet
-          werden:</p><pre class="programlisting">/etc/init.d/kivitendo-task-server start</pre></div><div class="sect3" title="2.7.3.2. Upstart-basierende Systeme (z.B. Ubuntu bis 14.04)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1446"></a>2.7.3.2. Upstart-basierende Systeme (z.B. Ubuntu bis 14.04)</h4></div></div></div><p>Kopieren Sie die Datei
+          werden:</p><pre class="programlisting">/etc/init.d/kivitendo-task-server start</pre></div><div class="sect3" title="2.7.3.2. Upstart-basierende Systeme (z.B. Ubuntu bis 14.04)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1489"></a>2.7.3.2. Upstart-basierende Systeme (z.B. Ubuntu bis 14.04)</h4></div></div></div><p>Kopieren Sie die Datei
           <code class="filename">scripts/boot/upstart/kivitendo-task-server.conf</code>
           nach <code class="filename">/etc/init/kivitendo-task-server.conf</code>.
           Passen Sie in der kopierten Datei den Pfad zum Task-Server an (Zeile
           <code class="literal">exec ....</code>).</p><p>Danach kann der Task-Server mit dem folgenden Befehl gestartet
-          werden:</p><pre class="programlisting">service kivitendo-task-server start</pre></div><div class="sect3" title="2.7.3.3. systemd-basierende Systeme (z.B. neure openSUSE, neuere Fedora, neuere Ubuntu und neuere Debians)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1464"></a>2.7.3.3. systemd-basierende Systeme (z.B. neure openSUSE, neuere
+          werden:</p><pre class="programlisting">service kivitendo-task-server start</pre></div><div class="sect3" title="2.7.3.3. systemd-basierende Systeme (z.B. neure openSUSE, neuere Fedora, neuere Ubuntu und neuere Debians)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1507"></a>2.7.3.3. systemd-basierende Systeme (z.B. neure openSUSE, neuere
           Fedora, neuere Ubuntu und neuere Debians)</h4></div></div></div><p>Kopieren Sie die Datei
           <code class="filename">scripts/boot/systemd/kivitendo-task-server.service</code>
           nach <code class="filename">/etc/systemd/system/</code>. Passen Sie in der
@@ -86,7 +86,7 @@ systemctl enable kivitendo-task-server.service</pre><p>Wenn Sie den Task-Server
             läuft.</p></li></ul></div><p>Der Task-Server wechselt beim Starten automatisch in das
         kivitendo-Installationsverzeichnis.</p><p>Dieselben Optionen können auch für die SystemV-basierenden
         Runlevel-Scripte benutzt werden (siehe oben).</p><p>Wurde der Task-Server als systemd-Service eingerichtet (s.o.),
-        so startet dieser nach Beendigung automatisch erneut.</p></div><div class="sect2" title="2.7.5. Exemplarische Konfiguration eines Hintergrund-Jobs, der die Jahreszahl in allen Nummernkreisen zum Jahreswechsel erhöht"><div class="titlepage"><div><div><h3 class="title"><a name="Tasks konfigurieren"></a>2.7.5. Exemplarische Konfiguration eines Hintergrund-Jobs, der die Jahreszahl in allen Nummernkreisen zum Jahreswechsel erhöht</h3></div></div></div><p>Hintergrund-Jobs werden über System -&gt; Hintergrund-Jobs und Task-Server -&gt; Aktuelle Hintergrund-Jobs anzeigen -&gt; Aktions-Knopf 'erfassen' angelegt. </p><p>Nachdem wir über das Menü dort angelangt sind, legen wir unseren exemplarischen Hintergrund-Jobs "Erhöhung der Nummernkreise" mit folgenden Werten an:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
+        so startet dieser nach Beendigung automatisch erneut.</p></div><div class="sect2" title="2.7.5. Exemplarische Konfiguration eines Hintergrund-Jobs, der die Jahreszahl in allen Nummernkreisen zum Jahreswechsel erhöht"><div class="titlepage"><div><div><h3 class="title"><a name="Tasks-konfigurieren"></a>2.7.5. Exemplarische Konfiguration eines Hintergrund-Jobs, der die Jahreszahl in allen Nummernkreisen zum Jahreswechsel erhöht</h3></div></div></div><p>Hintergrund-Jobs werden über System -&gt; Hintergrund-Jobs und Task-Server -&gt; Aktuelle Hintergrund-Jobs anzeigen -&gt; Aktions-Knopf 'erfassen' angelegt. </p><p>Nachdem wir über das Menü dort angelangt sind, legen wir unseren exemplarischen Hintergrund-Jobs "Erhöhung der Nummernkreise" mit folgenden Werten an:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                      <code class="literal">Aktiv:</code> Hier ein 'Ja' auswählen</p></li><li class="listitem"><p>
                      <code class="literal">Ausführungsart:</code> 'wiederholte Ausführung' auswählen</p></li><li class="listitem"><p>
                      <code class="literal">Paketname:</code> 'SetNumberRange' auswählen</p></li><li class="listitem"><p>
@@ -113,5 +113,7 @@ multiplier     Nummernkreis 2020
 10        -&gt;   20200
 100       -&gt;   202000
 1000      -&gt;   2020000
-</pre><p>Wir gehen jetzt beispielhaft von einer letzten Rechnungsnummer von RE2019456 aus. Demnach sollte ab Januar 2020 die erste Nummer RE2020001 sein. Da der Task auch Präfixe berücksichtigt, kann dies mit folgenden JSON-kodierten Werten umgesetzt werden:</p><code class="literal">Daten:</code><pre class="programlisting">multiplier: 100
+</pre><p>Wir gehen jetzt beispielhaft von einer letzten Rechnungsnummer von RE2019456 aus. Demnach sollte ab Januar 2020 die erste Nummer RE2020001 sein. Da der Task auch Präfixe berücksichtigt, kann dies mit folgenden JSON-kodierten Werten umgesetzt werden:</p><p>
+                     <code class="literal">Daten:</code>
+                  </p><pre class="programlisting">multiplier: 100
 digits_year: 4</pre></li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s06.html">Zurück</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Nach oben</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s08.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">2.6. Webserver-Konfiguration&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Zum Anfang</a></td><td width="40%" align="right" valign="top">&nbsp;2.8. Benutzerauthentifizierung und Administratorpasswort</td></tr></table></div></body></html>
\ No newline at end of file
index 7b206d1..d10b46c 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.8. Benutzerauthentifizierung und Administratorpasswort</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s07.html" title="2.7. Der Task-Server"><link rel="next" href="ch02s09.html" title="2.9. Mandanten-, Benutzer- und Gruppenverwaltung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.8. Benutzerauthentifizierung und Administratorpasswort</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s07.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s09.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.8. Benutzerauthentifizierung und Administratorpasswort"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Benutzerauthentifizierung-und-Administratorpasswort"></a>2.8. Benutzerauthentifizierung und Administratorpasswort</h2></div></div></div><p>Informationen über die Einrichtung der Benutzerauthentifizierung,
+   <title>2.8. Benutzerauthentifizierung und Administratorpasswort</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s07.html" title="2.7. Der Task-Server"><link rel="next" href="ch02s09.html" title="2.9. Mandanten-, Benutzer- und Gruppenverwaltung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.8. Benutzerauthentifizierung und Administratorpasswort</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s07.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s09.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.8. Benutzerauthentifizierung und Administratorpasswort"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Benutzerauthentifizierung-und-Administratorpasswort"></a>2.8. Benutzerauthentifizierung und Administratorpasswort</h2></div></div></div><p>Informationen über die Einrichtung der Benutzerauthentifizierung,
       über die Verwaltung von Gruppen und weitere Einstellungen</p><div class="sect2" title="2.8.1. Grundlagen zur Benutzerauthentifizierung"><div class="titlepage"><div><div><h3 class="title"><a name="Grundlagen-zur-Benutzerauthentifizierung"></a>2.8.1. Grundlagen zur Benutzerauthentifizierung</h3></div></div></div><p>kivitendo verwaltet die Benutzerinformationen in einer
         Datenbank, die im folgenden “Authentifizierungsdatenbank” genannt
         wird. Für jeden Benutzer kann dort eine eigene Datenbank für die
index ef81aed..8a718e6 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.9. Mandanten-, Benutzer- und Gruppenverwaltung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s08.html" title="2.8. Benutzerauthentifizierung und Administratorpasswort"><link rel="next" href="ch02s10.html" title="2.10. Drucker- und Systemverwaltung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.9. Mandanten-, Benutzer- und Gruppenverwaltung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s08.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s10.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.9. Mandanten-, Benutzer- und Gruppenverwaltung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Benutzer--und-Gruppenverwaltung"></a>2.9. Mandanten-, Benutzer- und Gruppenverwaltung</h2></div></div></div><p>Nach der Installation müssen Mandanten, Benutzer, Gruppen und
+   <title>2.9. Mandanten-, Benutzer- und Gruppenverwaltung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s08.html" title="2.8. Benutzerauthentifizierung und Administratorpasswort"><link rel="next" href="ch02s10.html" title="2.10. Drucker- und Systemverwaltung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.9. Mandanten-, Benutzer- und Gruppenverwaltung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s08.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s10.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.9. Mandanten-, Benutzer- und Gruppenverwaltung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Benutzer--und-Gruppenverwaltung"></a>2.9. Mandanten-, Benutzer- und Gruppenverwaltung</h2></div></div></div><p>Nach der Installation müssen Mandanten, Benutzer, Gruppen und
       Datenbanken angelegt werden. Dieses geschieht im Administrationsmenü,
       das Sie unter folgender URL finden:</p><p>
             <a class="ulink" href="http://localhost/kivitendo-erp/controller.pl?action=Admin/login" target="_top">http://localhost/kivitendo-erp/controller.pl?action=Admin/login</a>
index 1117308..1127acd 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.10. Drucker- und Systemverwaltung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s09.html" title="2.9. Mandanten-, Benutzer- und Gruppenverwaltung"><link rel="next" href="ch02s11.html" title="2.11. E-Mail-Versand aus kivitendo heraus"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.10. Drucker- und Systemverwaltung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s09.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s11.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.10. Drucker- und Systemverwaltung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Drucker--Systemverwaltung"></a>2.10. Drucker- und Systemverwaltung</h2></div></div></div><p>Im Administrationsmenü gibt es ferner noch die beiden Menüpunkte
+   <title>2.10. Drucker- und Systemverwaltung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s09.html" title="2.9. Mandanten-, Benutzer- und Gruppenverwaltung"><link rel="next" href="ch02s11.html" title="2.11. E-Mail-Versand aus kivitendo heraus"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.10. Drucker- und Systemverwaltung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s09.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s11.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.10. Drucker- und Systemverwaltung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Drucker--Systemverwaltung"></a>2.10. Drucker- und Systemverwaltung</h2></div></div></div><p>Im Administrationsmenü gibt es ferner noch die beiden Menüpunkte
       Druckeradministration und System.</p><div class="sect2" title="2.10.1. Druckeradministration"><div class="titlepage"><div><div><h3 class="title"><a name="Druckeradministration"></a>2.10.1. Druckeradministration</h3></div></div></div><p>Unter dem Menüpunkt Druckeradministration lassen sich beliebig
         viele "Druckbefehle" im System verwalten. Diese Befehle werden
         mandantenweise zugeordnet. Unter Druckerbeschreibung wird der Namen
index e1a56fd..c2ce198 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.11. E-Mail-Versand aus kivitendo heraus</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s10.html" title="2.10. Drucker- und Systemverwaltung"><link rel="next" href="ch02s12.html" title="2.12. Drucken mit kivitendo"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.11. E-Mail-Versand aus kivitendo heraus</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s10.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s12.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.11. E-Mail-Versand aus kivitendo heraus"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.sending-email"></a>2.11. E-Mail-Versand aus kivitendo heraus</h2></div></div></div><p>kivitendo kann direkt aus dem Programm heraus E-Mails versenden,
+   <title>2.11. E-Mail-Versand aus kivitendo heraus</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s10.html" title="2.10. Drucker- und Systemverwaltung"><link rel="next" href="ch02s12.html" title="2.12. Drucken mit kivitendo"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.11. E-Mail-Versand aus kivitendo heraus</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s10.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s12.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.11. E-Mail-Versand aus kivitendo heraus"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.sending-email"></a>2.11. E-Mail-Versand aus kivitendo heraus</h2></div></div></div><p>kivitendo kann direkt aus dem Programm heraus E-Mails versenden,
       z.B. um ein Angebot direkt an einen Kunden zu verschicken. Damit dies
       funktioniert, muss eingestellt werden, über welchen Server die E-Mails
       verschickt werden sollen. kivitendo unterstützt dabei zwei Mechanismen:
index b69b368..8c7835f 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.12. Drucken mit kivitendo</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s11.html" title="2.11. E-Mail-Versand aus kivitendo heraus"><link rel="next" href="ch02s13.html" title="2.13. OpenDocument-Vorlagen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.12. Drucken mit kivitendo</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s11.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s13.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.12. Drucken mit kivitendo"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Drucken-mit-kivitendo"></a>2.12. Drucken mit kivitendo</h2></div></div></div><p>Das Drucksystem von kivitendo benutzt von Haus aus LaTeX-Vorlagen.
+   <title>2.12. Drucken mit kivitendo</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s11.html" title="2.11. E-Mail-Versand aus kivitendo heraus"><link rel="next" href="ch02s13.html" title="2.13. OpenDocument-Vorlagen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.12. Drucken mit kivitendo</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s11.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s13.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.12. Drucken mit kivitendo"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Drucken-mit-kivitendo"></a>2.12. Drucken mit kivitendo</h2></div></div></div><p>Das Drucksystem von kivitendo benutzt von Haus aus LaTeX-Vorlagen.
       Um drucken zu können, braucht der Server ein geeignetes LaTeX System. Am
       einfachsten ist dazu eine <code class="literal">texlive</code> Installation. Unter
       debianoiden Betriebssystemen installiert man die Pakete mit:</p><p>
             </p><pre class="programlisting">zypper install texlive-collection-latex texlive-collection-latexextra \
   texlive-collection-latexrecommended texlive-collection-langgerman \
   texlive-collection-langenglish</pre><p>
-         </p><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left">Anmerkung</th></tr><tr><td align="left" valign="top">kivitendo erwartet eine aktuelle TeX Live Umgebung, um PDF/A zu erzeugen. Aktuelle Distributionen von 2020 erfüllen diese. Überprüfbar ist dies mit dem Aufruf des installation_check.pl mit Parameter -l: <pre class="programlisting">scripts/installations_check.pl -l</pre></td></tr></table></div><p>kivitendo bringt drei alternative Vorlagensätze mit:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>RB</p></li><li class="listitem"><p>marei</p></li><li class="listitem"><p>rev-odt</p></li></ul></div><p>Der ehemalige Druckvorlagensatz "f-tex" wurde mit der Version
-      3.6 entfernt, da er nicht mehr gepflegt wird.</p><div class="sect2" title="2.12.1. Vorlagenverzeichnis anlegen"><div class="titlepage"><div><div><h3 class="title"><a name="Vorlagenverzeichnis-anlegen"></a>2.12.1. Vorlagenverzeichnis anlegen</h3></div></div></div><p>Es lässt sich ein initialer Vorlagensatz erstellen. Die
+         </p><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left">Anmerkung</th></tr><tr><td align="left" valign="top"><p>kivitendo erwartet eine aktuelle TeX Live Umgebung, um PDF/A zu erzeugen. Aktuelle Distributionen von 2020 erfüllen diese. Überprüfbar ist dies mit dem Aufruf des installation_check.pl mit Parameter -l:</p><p>
+               </p><pre class="programlisting">scripts/installations_check.pl -l</pre><p>
+            </p></td></tr></table></div><p>kivitendo bringt drei alternative Vorlagensätze mit:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>RB</p></li><li class="listitem"><p>marei</p></li><li class="listitem"><p>rev-odt</p></li></ul></div><p>Der ehemalige Druckvorlagensatz "f-tex" wurde mit der Version
+      3.5.6 entfernt, da er nicht mehr gepflegt wird.</p><div class="sect2" title="2.12.1. Vorlagenverzeichnis anlegen"><div class="titlepage"><div><div><h3 class="title"><a name="Vorlagenverzeichnis-anlegen"></a>2.12.1. Vorlagenverzeichnis anlegen</h3></div></div></div><p>Es lässt sich ein initialer Vorlagensatz erstellen. Die
         LaTeX-System-Abhängigkeiten hierfür kann man prüfen mit:</p><pre class="programlisting">./scripts/installation_check.pl -lv</pre><p>Der Angemeldete Benutzer muss in einer Gruppe sein, die über das
         Recht "Konfiguration -&gt; Mandantenverwaltung" verfügt. Siehe auch
         <a class="xref" href="ch02s09.html#Gruppen-anlegen" title="2.9.4. Gruppen anlegen">Abschnitt&nbsp;2.9.4, „Gruppen anlegen“</a>.</p><p>Im Userbereich lässt sich unter: "<span class="guimenu">System</span>
index 18ed120..ed0cdfb 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.13. OpenDocument-Vorlagen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s12.html" title="2.12. Drucken mit kivitendo"><link rel="next" href="ch02s14.html" title="2.14. Nomenklatur"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.13. OpenDocument-Vorlagen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s12.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s14.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.13. OpenDocument-Vorlagen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="OpenDocument-Vorlagen"></a>2.13. OpenDocument-Vorlagen</h2></div></div></div><p>kivitendo unterstützt die Verwendung von Vorlagen im
+   <title>2.13. OpenDocument-Vorlagen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s12.html" title="2.12. Drucken mit kivitendo"><link rel="next" href="ch02s14.html" title="2.14. Nomenklatur"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.13. OpenDocument-Vorlagen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s12.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s14.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.13. OpenDocument-Vorlagen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="OpenDocument-Vorlagen"></a>2.13. OpenDocument-Vorlagen</h2></div></div></div><p>kivitendo unterstützt die Verwendung von Vorlagen im
       OpenDocument-Format, wie es LibreOffice oder OpenOffice (ab Version 2)
       erzeugen. kivitendo kann dabei sowohl neue OpenDocument-Dokumente als
       auch aus diesen direkt PDF-Dateien erzeugen. Um die Unterstützung von
       Verzeichnis umbenannt werden.</p><p>Dieses Verzeichnis, wie auch das komplette
       <code class="literal">users</code>-Verzeichnis, muss vom Webserver beschreibbar
       sein. Dieses wurde bereits erledigt (siehe <a class="xref" href="ch02s03.html" title="2.3. Manuelle Installation des Programmpaketes">Manuelle Installation des Programmpaketes</a>), kann aber erneut
-      überprüft werden, wenn die Konvertierung nach PDF fehlschlägt.</p><div class="sect2" title="2.13.1. OpenDocument (odt) Druckvorlagen mit Makros"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2440"></a>2.13.1. OpenDocument (odt) Druckvorlagen mit Makros</h3></div></div></div><p>OpenDocument Vorlagen können Makros enthalten, welche komplexere
+      überprüft werden, wenn die Konvertierung nach PDF fehlschlägt.</p><div class="sect2" title="2.13.1. OpenDocument (odt) Druckvorlagen mit Makros"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2489"></a>2.13.1. OpenDocument (odt) Druckvorlagen mit Makros</h3></div></div></div><p>OpenDocument Vorlagen können Makros enthalten, welche komplexere
         Aufgaben erfüllen.</p><p>Der Vorlagensatz "rev-odt" enthält solche Vorlagen mit <span class="bold"><strong>Schweizer Bank-Einzahlungsscheinen (BESR)</strong></span>.
         Diese Makros haben die Aufgabe, die in den Einzahlungsscheinen
         benötigte Referenznummer und Kodierzeile zu erzeugen. Hier eine kurze
         Beschreibung, wie die Makros aufgebaut sind, und was bei ihrer Nutzung
         zu beachten ist (<span class="bold"><strong>in fett sind nötige einmalige
-        Anpassungen aufgeführt</strong></span>):</p><div class="sect3" title="2.13.1.1. Bezeichnung der Vorlagen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2453"></a>2.13.1.1. Bezeichnung der Vorlagen</h4></div></div></div><p>Rechnung: invoice_besr.odt, Auftrag:
-          sales_order_besr.odt</p></div><div class="sect3" title="2.13.1.2. Vorbereitungen im Adminbereich"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2458"></a>2.13.1.2. Vorbereitungen im Adminbereich</h4></div></div></div><p>Damit beim Erstellen von Rechnungen und Aufträgen neben der
+        Anpassungen aufgeführt</strong></span>):</p><div class="sect3" title="2.13.1.1. Bezeichnung der Vorlagen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2502"></a>2.13.1.1. Bezeichnung der Vorlagen</h4></div></div></div><p>Rechnung: invoice_besr.odt, Auftrag:
+          sales_order_besr.odt</p></div><div class="sect3" title="2.13.1.2. Vorbereitungen im Adminbereich"><div class="titlepage"><div><div><h4 class="title"><a name="opendocument-druckvorlagen-mit-makros.vorbereitungen"></a>2.13.1.2. Vorbereitungen im Adminbereich</h4></div></div></div><p>Damit beim Erstellen von Rechnungen und Aufträgen neben der
           Standardvorlage ohne Einzahlungsschein weitere Vorlagen (z.B. mit
           Einzahlungsschein) auswählbar sind, muss für jedes Vorlagen-Suffix
           ein Drucker eingerichtet werden:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Druckeradministration → Drucker hinzufügen</p></li><li class="listitem"><p>Mandant wählen</p></li><li class="listitem"><p>Druckerbeschreibung → aussagekräftiger Text: wird in der
               Aufträgen oder Rechnungen als odt-Datei keine Bedeutung, darf
               aber nicht leer sein)</p></li><li class="listitem"><p>Vorlagenkürzel → besr bzw. selbst gewähltes Vorlagensuffix
               (muss genau der Zeichenfolge entsprechen, die zwischen
-              "invoice_" bzw. "sales_order_" und ".odt" steht.)</p></li><li class="listitem"><p>speichern</p></li></ul></div></div><div class="sect3" title="2.13.1.3. Benutzereinstellungen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2482"></a>2.13.1.3. Benutzereinstellungen</h4></div></div></div><p>Wer den Ausdruck mit Einzahlungsschein als Standardeinstellung
+              "invoice_" bzw. "sales_order_" und ".odt" steht.)</p></li><li class="listitem"><p>speichern</p></li></ul></div></div><div class="sect3" title="2.13.1.3. Benutzereinstellungen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2531"></a>2.13.1.3. Benutzereinstellungen</h4></div></div></div><p>Wer den Ausdruck mit Einzahlungsschein als Standardeinstellung
           im Rechnungs- bzw. Auftragsformular angezeigt haben möchte, kann
           dies persönlich für sich bei den Benutzereinstellungen
           konfigurieren:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Programm → Benutzereinstellungen → Druckoptionen</p></li><li class="listitem"><p>Standardvorlagenformat → OpenDocument/OASIS</p></li><li class="listitem"><p>Standardausgabekanal → Bildschirm</p></li><li class="listitem"><p>Standarddrucker → gewünschte Druckerbeschreibung auswählen
-              (z.B. mit Einzahlungsschein Bank xy)</p></li><li class="listitem"><p>Anzahl Kopien → leer</p></li><li class="listitem"><p>speichern</p></li></ul></div></div><div class="sect3" title="2.13.1.4. Aufbau und nötige Anpassungen der Vorlagen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2506"></a>2.13.1.4. Aufbau und nötige Anpassungen der Vorlagen</h4></div></div></div><p>In der Vorlage sind als Modul "BESR" 4 Makros gespeichert, die
+              (z.B. mit Einzahlungsschein Bank xy)</p></li><li class="listitem"><p>Anzahl Kopien → leer</p></li><li class="listitem"><p>speichern</p></li></ul></div></div><div class="sect3" title="2.13.1.4. Aufbau und nötige Anpassungen der Vorlagen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2555"></a>2.13.1.4. Aufbau und nötige Anpassungen der Vorlagen</h4></div></div></div><p>In der Vorlage sind als Modul "BESR" 4 Makros gespeichert, die
           aus dem von kivitendo erzeugten odt-Dokument die korrekte
           Referenznummer inklusive Prüfziffer sowie die Kodierzeile in
           OCRB-Schrift erzeugen und am richtigen Ort ins Dokument
               angepasst werden.</strong></span> Dabei ist darauf zu achten, dass
               sich die Positionen der Postkonto-Nummern der Bank, sowie der
               Zeichenfolgen dddfr, DDDREF1, DDDREF2, 609, DDDKODIERZEILE nicht
-              verschieben.</p></li></ul></div><div class="screenshot"><div class="mediaobject"><img src="images/Einzahlungsschein_Makro.png"></div></div></div><div class="sect3" title="2.13.1.5. Auswahl der Druckvorlage in kivitendo beim Erzeugen einer odt-Rechnung (analog bei Auftrag)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2570"></a>2.13.1.5. Auswahl der Druckvorlage in kivitendo beim Erzeugen einer
+              verschieben.</p></li></ul></div><div class="screenshot"><div class="mediaobject"><img src="images/Einzahlungsschein_Makro.png"></div></div></div><div class="sect3" title="2.13.1.5. Auswahl der Druckvorlage in kivitendo beim Erzeugen einer odt-Rechnung (analog bei Auftrag)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2619"></a>2.13.1.5. Auswahl der Druckvorlage in kivitendo beim Erzeugen einer
           odt-Rechnung (analog bei Auftrag)</h4></div></div></div><p>Im Fussbereich der Rechnungsmaske muss neben Rechnung,
           OpenDocument/OASIS und Bildschirm die im Adminbereich erstellte
           Druckerbeschreibung ausgewählt werden, falls diese nicht bereits bei
           den Benutzereinstellungen als persönlicher Standard gewählt
-          wurde.</p></div><div class="sect3" title="2.13.1.6. Makroeinstellungen in LibreOffice anpassen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2575"></a>2.13.1.6. Makroeinstellungen in LibreOffice anpassen</h4></div></div></div><p>Falls beim Öffnen einer von kivitendo erzeugten odt-Rechnung
+          wurde.</p></div><div class="sect3" title="2.13.1.6. Makroeinstellungen in LibreOffice anpassen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2624"></a>2.13.1.6. Makroeinstellungen in LibreOffice anpassen</h4></div></div></div><p>Falls beim Öffnen einer von kivitendo erzeugten odt-Rechnung
           die Meldung kommt, dass Makros aus Sicherheitsgründen nicht
           ausgeführt werden, so müssen folgende Einstellungen in LibreOffice
           angepasst werden:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Extras → Optionen → Sicherheit → Makrosicherheit</p></li><li class="listitem"><p>Sicherheitslevel auf "Mittel" einstellen (Diese
               so eingestellt, dass sie beim Öffnen der Vorlagen selbst nicht
               ausgeführt werden. Das heisst für das Ansehen und Bearbeiten der
               Vorlagen sind keine speziellen Einstellungen in LibreOffice
-              nötig.</p></li></ul></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s12.html">Zurück</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Nach oben</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s14.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">2.12. Drucken mit kivitendo&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Zum Anfang</a></td><td width="40%" align="right" valign="top">&nbsp;2.14. Nomenklatur</td></tr></table></div></body></html>
\ No newline at end of file
+              nötig.</p></li></ul></div></div></div><div class="sect2" title="2.13.2. Schweizer QR-Rechnung mit OpenDocument Vorlagen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2644"></a>2.13.2. Schweizer QR-Rechnung mit OpenDocument Vorlagen</h3></div></div></div><div class="sect3" title="2.13.2.1. Übersicht"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2647"></a>2.13.2.1. Übersicht</h4></div></div></div><p>Mit der Version 3.6.0 unterstützt Kivitendo die Erstellung von
+          Schweizer QR-Rechnungen gemäss <a class="ulink" href="https://www.paymentstandards.ch/dam/downloads/ig-qr-bill-de.pdf" target="_top">Swiss
+          Payment Standards, Version 2.2</a>. Implementiert sind hierbei die
+          Varianten:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
+                        <span class="bold"><strong>QR-IBAN mit
+              QR-Referenz</strong></span>
+                     </p></li><li class="listitem"><p>
+                        <span class="bold"><strong>IBAN ohne Referenz</strong></span>
+                     </p></li></ul></div><p>Der Vorlagensatz "rev-odt" enthält die Vorlage
+          <code class="literal">invoice_qr.odt</code>, welche für die Erstellung von
+          QR-Rechnungen vorgesehen ist. Damit diese verwendet werden kann muss
+          wie obenstehend beschrieben ein Drucker hinzugefügt werden (siehe
+          <a class="xref" href="ch02s13.html#opendocument-druckvorlagen-mit-makros.vorbereitungen" title="2.13.1.2. Vorbereitungen im Adminbereich">Abschnitt&nbsp;2.13.1.2, „Vorbereitungen im Adminbereich“</a>
+          ). Alternativ kann die Vorlage umbenannt werden in
+          <code class="literal">invoice.odt</code>.</p><p>Die Vorlage <code class="literal">invoice_qr.odt</code> kann beliebig
+          angepasst werden. Zwingend muss diese jedoch das QR-Code Platzhalter
+          Bild, als eingebettetes Bild, enthalten. Da dieses beim
+          Ausdrucken/Erzeugen der Rechnung durch das neu generierte QR-Code
+          Bild ersetzt wird.</p></div><div class="sect3" title="2.13.2.2. Einstellungen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2683"></a>2.13.2.2. Einstellungen</h4></div></div></div><div class="sect4" title="2.13.2.2.1. Mandantenkonfiguration"><div class="titlepage"><div><div><h5 class="title"><a name="d0e2686"></a>2.13.2.2.1. Mandantenkonfiguration</h5></div></div></div><p>Unter <span class="emphasis"><em>System → Mandantenkonfiguration →
+            Features</em></span>. Im Abschnitt <span class="emphasis"><em>Einkauf und
+            Verkauf</em></span>, beim Punkt <span class="emphasis"><em>Verkaufsrechnungen mit
+            Schweizer QR-Rechnung erzeugen</em></span>, die gewünschte Variante
+            wählen.</p></div><div class="sect4" title="2.13.2.2.2. Konfiguration der Bankkonten"><div class="titlepage"><div><div><h5 class="title"><a name="d0e2700"></a>2.13.2.2.2. Konfiguration der Bankkonten</h5></div></div></div><p>Unter <span class="emphasis"><em>System → Bankkonten</em></span> muss bei
+            mindestens einem Bankkonto die Option <span class="emphasis"><em>Nutzung mit
+            Schweizer QR-Rechnung</em></span> auf <span class="bold"><strong>Ja</strong></span> gestellt werden.</p><div class="tip" title="Tipp" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tipp]" src="system/docbook-xsl/images/tip.png"></td><th align="left">Tipp</th></tr><tr><td align="left" valign="top"><p>Für die Variante <span class="bold"><strong>QR-IBAN mit
+              QR-Referenz</strong></span> muss dieses Konto unter IBAN eine gültige
+              <span class="bold"><strong>QR-IBAN Nummer</strong></span> enthalten. Diese
+              unterscheidet sich von der regulären IBAN.</p><p>Zusätzlich muss eine gültige <span class="bold"><strong>Bankkonto
+              Identifikationsnummer</strong></span> angegeben werden
+              (6-stellig).</p><p>Diese werden von der jeweiligen Bank vergeben.</p></td></tr></table></div><p>Sind mehrere Konten ausgewählt wird das erste
+            verwendet.</p></div><div class="sect4" title="2.13.2.2.3. Rechnungen ohne Betrag"><div class="titlepage"><div><div><h5 class="title"><a name="d0e2732"></a>2.13.2.2.3. Rechnungen ohne Betrag</h5></div></div></div><p>Für Rechnungen ohne Betrag (z.B. Spenden) kann, in der
+            jeweiligen Rechnung, die Checkbox <span class="emphasis"><em>QR-Rechnung ohne
+            Betrag</em></span> aktiviert werden. Diese Checkbox erscheint nur,
+            wenn QR-Rechnungen in der Mandantenkonfiguration aktiviert sind
+            (variante ausgewählt).</p><p>Dies wirkt sich lediglich auf den erzeugten QR-Code aus. Die
+            Vorlage muss separat angepasst und ausgewählt werden.</p></div></div><div class="sect3" title="2.13.2.3. Adressdaten"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2742"></a>2.13.2.3. Adressdaten</h4></div></div></div><p>Die Adressdaten zum Zahlungsempfänger werden aus der
+          Mandantenkonfiguration entnommen. Unter <span class="emphasis"><em>System →
+          Mandantenkonfiguration → Verschiedenes</em></span>, Abschnitt
+          <span class="emphasis"><em>Firmenname und -adresse.</em></span>
+               </p><p>Die Adressdaten zum Zahlungspflichtigen stammen aus den
+          Kundendaten der jeweiligen Rechnung.</p><p>Die Adressen müssen inklusive Land angegeben werden. Akzeptiert
+          werden Ländername oder Ländercode, also z.B. "Schweiz" oder "CH".
+          </p><p>Diese können in der Vorlage mit den jeweiligen Variablen
+          eingetragen werden. Siehe auch: <a class="xref" href="ch03s03.html" title="3.3. Dokumentenvorlagen und verfügbare Variablen">Abschnitt&nbsp;3.3, „Dokumentenvorlagen und verfügbare Variablen“</a>
+               </p><p>Der erzeugte QR-Code verwendet Adress-Typ "K" (Kombinierte
+          Adressfelder, 2 Zeilen).</p></div><div class="sect3" title="2.13.2.4. Referenznummer"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2763"></a>2.13.2.4. Referenznummer</h4></div></div></div><p>Die Referenznummer wird in Kivitendo erzeugt und setzt sich
+          wiefolgt zusammen:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Bankkonto Identifikationsnummer (6-stellig)</p></li><li class="listitem"><p>Kundennummer (6-stellig, mit führenden Nullen
+              aufgefüllt)</p></li><li class="listitem"><p>Auftragsnummer (7-stellig, mit führenden Nullen
+              aufgefüllt)</p></li><li class="listitem"><p>Rechnungsnummer (7-stellig, mit führenden Nullen
+              aufgefüllt)</p></li><li class="listitem"><p>Prüfziffer (1-stellig, berechnet mittels modulo 10,
+              rekursiv)</p></li></ul></div><p>Es sind lediglich Ziffern erlaubt. Allfällige Prefixe mit
+          Buchstaben werden entfernt und fehlende Stellen werden mit führenden
+          Nullen aufgefüllt.</p></div><div class="sect3" title="2.13.2.5. Zusätzliche Variablen für Vorlage"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2786"></a>2.13.2.5. Zusätzliche Variablen für Vorlage</h4></div></div></div><p>Zusätzlich zu den in der Vorlage standardmässig verfügbaren
+          Variablen (siehe <a class="xref" href="ch03s03.html" title="3.3. Dokumentenvorlagen und verfügbare Variablen">Abschnitt&nbsp;3.3, „Dokumentenvorlagen und verfügbare Variablen“</a>),
+          werden die folgenden Variablen erzeugt:</p><div class="variablelist"><dl><dt><span class="term">ref_number_formatted</span></dt><dd><p>Referenznummer formatiert mit Leerzeichen, z.B.: 21 00000
+                00003 13947 14300 09017</p></dd><dt><span class="term">iban_formatted</span></dt><dd><p>IBAN formatiert mit Leerzeichen</p></dd><dt><span class="term">amount_formatted</span></dt><dd><p>Betrag formatiert mit Tausendertrennzeichen Leerschlag,
+                z.B.: 1 005.55</p></dd></dl></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s12.html">Zurück</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Nach oben</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch02s14.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">2.12. Drucken mit kivitendo&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Zum Anfang</a></td><td width="40%" align="right" valign="top">&nbsp;2.14. Nomenklatur</td></tr></table></div></body></html>
\ No newline at end of file
index 6bfb0fc..305687c 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.14. Nomenklatur</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s13.html" title="2.13. OpenDocument-Vorlagen"><link rel="next" href="ch02s15.html" title="2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung: EUR"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.14. Nomenklatur</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s13.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s15.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.14. Nomenklatur"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="nomenclature"></a>2.14. Nomenklatur</h2></div></div></div><div class="sect2" title="2.14.1. Datum bei Buchungen"><div class="titlepage"><div><div><h3 class="title"><a name="booking.dates"></a>2.14.1. Datum bei Buchungen</h3></div></div></div><p>Seit der Version 3.5 werden für Buchungen in kivitendo
+   <title>2.14. Nomenklatur</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s13.html" title="2.13. OpenDocument-Vorlagen"><link rel="next" href="ch02s15.html" title="2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung: EUR"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.14. Nomenklatur</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s13.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s15.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.14. Nomenklatur"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="nomenclature"></a>2.14. Nomenklatur</h2></div></div></div><div class="sect2" title="2.14.1. Datum bei Buchungen"><div class="titlepage"><div><div><h3 class="title"><a name="booking.dates"></a>2.14.1. Datum bei Buchungen</h3></div></div></div><p>Seit der Version 3.5 werden für Buchungen in kivitendo
         einheitlich folgende Bezeichnungen verwendet:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                      <code class="option">Erfassungsdatum</code> (en: <code class="option">Entry
             Date</code>, code: <code class="option">Gldate</code>)</p><p>bezeichnet das Datum, an dem die Buchung in kivitendo
index f4fa77e..24f58c3 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung: EUR</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s14.html" title="2.14. Nomenklatur"><link rel="next" href="ch02s16.html" title="2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung:
+   <title>2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung: EUR</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s14.html" title="2.14. Nomenklatur"><link rel="next" href="ch02s16.html" title="2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung:
       EUR</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s14.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s16.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung: EUR"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.eur"></a>2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung:
       EUR</h2></div></div></div><div class="sect2" title="2.15.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="config.eur.introduction"></a>2.15.1. Einführung</h3></div></div></div><p>kivitendo besaß bis inklusive Version 2.6.3 einen
         Konfigurationsparameter namens <code class="varname">eur</code>, der sich in der
index f58fb8e..13e79cf 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s15.html" title="2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung: EUR"><link rel="next" href="ch02s17.html" title="2.17. Verhalten des Bilanzberichts"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s15.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s17.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.skr04-update-3804"></a>2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb</h2></div></div></div><div class="sect2" title="2.16.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="config.skr04-update-3804.introduction"></a>2.16.1. Einführung</h3></div></div></div><p>Die Umsatzsteuerumstellung auf 19% für SKR04 für die
+   <title>2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s15.html" title="2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung: EUR"><link rel="next" href="ch02s17.html" title="2.17. Verhalten des Bilanzberichts"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s15.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s17.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.skr04-update-3804"></a>2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb</h2></div></div></div><div class="sect2" title="2.16.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="config.skr04-update-3804.introduction"></a>2.16.1. Einführung</h3></div></div></div><p>Die Umsatzsteuerumstellung auf 19% für SKR04 für die
         Steuerschlüssel "EU ohne USt-ID Nummer" ist erst 2010 erfolgt.
         kivitendo beinhaltet ein Upgradeskript, das das Konto 3804 automatisch
         erstellt und die Steuereinstellungen korrekt einstellt. Hat der
index aefaf2c..a5030e6 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.17. Verhalten des Bilanzberichts</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s16.html" title="2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb"><link rel="next" href="ch02s18.html" title="2.18. Erfolgsrechnung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.17. Verhalten des Bilanzberichts</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s16.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s18.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.17. Verhalten des Bilanzberichts"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.bilanz"></a>2.17. Verhalten des Bilanzberichts</h2></div></div></div><p>Bis Version 3.0 wurde "closedto" ("Bücher schließen zum") als
+   <title>2.17. Verhalten des Bilanzberichts</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s16.html" title="2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb"><link rel="next" href="ch02s18.html" title="2.18. Erfolgsrechnung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.17. Verhalten des Bilanzberichts</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s16.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s18.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.17. Verhalten des Bilanzberichts"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.bilanz"></a>2.17. Verhalten des Bilanzberichts</h2></div></div></div><p>Bis Version 3.0 wurde "closedto" ("Bücher schließen zum") als
       Grundlage für das Startdatum benutzt. Schließt man die Bücher allerdings
       monatsweise führt dies zu falschen Werten.</p><p>In der Mandantenkonfiguration kann man dieses Verhalten genau
       einstellen indem man:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>weiterhin closed_to benutzt (Default, es ändert sich nichts zu
index 69e2df1..2641cdd 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.18. Erfolgsrechnung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s17.html" title="2.17. Verhalten des Bilanzberichts"><link rel="next" href="ch02s19.html" title="2.19. Rundung in Verkaufsbelegen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.18. Erfolgsrechnung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s17.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s19.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.18. Erfolgsrechnung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.erfolgsrechnung"></a>2.18. Erfolgsrechnung</h2></div></div></div><p>Seit der Version 3.4.1 existiert in kivitendo der Bericht
+   <title>2.18. Erfolgsrechnung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s17.html" title="2.17. Verhalten des Bilanzberichts"><link rel="next" href="ch02s19.html" title="2.19. Rundung in Verkaufsbelegen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.18. Erfolgsrechnung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s17.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s19.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.18. Erfolgsrechnung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.erfolgsrechnung"></a>2.18. Erfolgsrechnung</h2></div></div></div><p>Seit der Version 3.4.1 existiert in kivitendo der Bericht
       <span class="bold"><strong> Erfolgsrechnung</strong></span>.</p><p>Die Erfolgsrechnung kann in der Mandantenkonfiguration unter
       Features an- oder abgeschaltet werden. Mit der Einstellung
       <code class="varname">default_manager = swiss </code> in der
index 2d6c4db..8ef8569 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.19. Rundung in Verkaufsbelegen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s18.html" title="2.18. Erfolgsrechnung"><link rel="next" href="ch02s20.html" title="2.20. Einstellungen pro Mandant"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.19. Rundung in Verkaufsbelegen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s18.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s20.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.19. Rundung in Verkaufsbelegen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.rounding"></a>2.19. Rundung in Verkaufsbelegen</h2></div></div></div><p>In der Schweiz hat die kleinste aktuell benutzte Münze den Wert
+   <title>2.19. Rundung in Verkaufsbelegen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s18.html" title="2.18. Erfolgsrechnung"><link rel="next" href="ch02s20.html" title="2.20. Einstellungen pro Mandant"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.19. Rundung in Verkaufsbelegen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s18.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s20.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.19. Rundung in Verkaufsbelegen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.rounding"></a>2.19. Rundung in Verkaufsbelegen</h2></div></div></div><p>In der Schweiz hat die kleinste aktuell benutzte Münze den Wert
       von 5 Rappen (0.05 CHF).</p><p>Auch wenn im elektronischen Zahlungsverkehr Beträge mit einer
       Genauigkeit von 0.01 CHF verwendet werden können, ist es trotzdem nach
       wie vor üblich, Rechnungen mit auf 0.05 CHF gerundeten Beträgen
index 9d2a87b..ac383fb 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.20. Einstellungen pro Mandant</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s19.html" title="2.19. Rundung in Verkaufsbelegen"><link rel="next" href="ch02s21.html" title="2.21. kivitendo ERP verwenden"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.20. Einstellungen pro Mandant</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s19.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s21.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.20. Einstellungen pro Mandant"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.client"></a>2.20. Einstellungen pro Mandant</h2></div></div></div><p>Einige Einstellungen können von einem Benutzer mit dem <a class="link" href="ch02s09.html#Zusammenh%C3%A4nge" title="2.9.1. Zusammenhänge">Recht</a> "Administration (Für die Verwaltung
+   <title>2.20. Einstellungen pro Mandant</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s19.html" title="2.19. Rundung in Verkaufsbelegen"><link rel="next" href="ch02s21.html" title="2.21. kivitendo ERP verwenden"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.20. Einstellungen pro Mandant</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s19.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s21.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.20. Einstellungen pro Mandant"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="config.client"></a>2.20. Einstellungen pro Mandant</h2></div></div></div><p>Einige Einstellungen können von einem Benutzer mit dem <a class="link" href="ch02s09.html#Zusammenh%C3%A4nge" title="2.9.1. Zusammenhänge">Recht</a> "Administration (Für die Verwaltung
       der aktuellen Instanz aus einem Userlogin heraus)" gemacht werden. Diese
       Einstellungen sind dann für die aktuellen Mandanten-Datenbank gültig.
       Die Einstellungen sind unter <span class="guimenu">System</span> →
index 5bdc63a..2bad9f7 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.21. kivitendo ERP verwenden</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s20.html" title="2.20. Einstellungen pro Mandant"><link rel="next" href="ch03.html" title="Kapitel 3. Features und Funktionen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.21. kivitendo ERP verwenden</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s20.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.21. kivitendo ERP verwenden"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="kivitendo-ERP-verwenden"></a>2.21. kivitendo ERP verwenden</h2></div></div></div><p>Nach erfolgreicher Installation ist der Loginbildschirm unter
+   <title>2.21. kivitendo ERP verwenden</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s20.html" title="2.20. Einstellungen pro Mandant"><link rel="next" href="ch03.html" title="Kapitel 3. Features und Funktionen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.21. kivitendo ERP verwenden</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s20.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.21. kivitendo ERP verwenden"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="kivitendo-ERP-verwenden"></a>2.21. kivitendo ERP verwenden</h2></div></div></div><p>Nach erfolgreicher Installation ist der Loginbildschirm unter
       folgender URL erreichbar:</p><p>
             <a class="ulink" href="http://localhost/kivitendo-erp/login.pl" target="_top">http://localhost/kivitendo-erp/login.pl</a>
          </p><p>Die Administrationsseite erreichen Sie unter:</p><p>
index 8e5882a..d75edb0 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>Kapitel 3. Features und Funktionen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="prev" href="ch02s21.html" title="2.21. kivitendo ERP verwenden"><link rel="next" href="ch03s02.html" title="3.2. Bankerweiterung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 3. Features und Funktionen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s21.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 3. Features und Funktionen"><div class="titlepage"><div><div><h2 class="title"><a name="features"></a>Kapitel 3. Features und Funktionen</h2></div></div></div><div class="sect1" title="3.1. Wiederkehrende Rechnungen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.periodic-invoices"></a>3.1. Wiederkehrende Rechnungen</h2></div></div></div><div class="sect2" title="3.1.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="features.periodic-invoices.introduction"></a>3.1.1. Einführung</h3></div></div></div><p>Wiederkehrende Rechnungen werden als normale Aufträge definiert
+   <title>Kapitel 3. Features und Funktionen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="prev" href="ch02s21.html" title="2.21. kivitendo ERP verwenden"><link rel="next" href="ch03s02.html" title="3.2. Bankerweiterung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 3. Features und Funktionen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s21.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 3. Features und Funktionen"><div class="titlepage"><div><div><h2 class="title"><a name="features"></a>Kapitel 3. Features und Funktionen</h2></div></div></div><div class="sect1" title="3.1. Wiederkehrende Rechnungen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.periodic-invoices"></a>3.1. Wiederkehrende Rechnungen</h2></div></div></div><div class="sect2" title="3.1.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="features.periodic-invoices.introduction"></a>3.1.1. Einführung</h3></div></div></div><p>Wiederkehrende Rechnungen werden als normale Aufträge definiert
         und konfiguriert, mit allen dazugehörigen Kunden- und Artikelangaben.
         Die konfigurierten Aufträge werden später automatisch in Rechnungen
         umgewandelt, so als ob man den Workflow benutzen würde, und auch die
index 96b0b78..1c2668d 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.2. Bankerweiterung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="next" href="ch03s03.html" title="3.3. Dokumentenvorlagen und verfügbare Variablen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.2. Bankerweiterung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s03.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.2. Bankerweiterung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.bank"></a>3.2. Bankerweiterung</h2></div></div></div><div class="sect2" title="3.2.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="features.bank.introduction"></a>3.2.1. Einführung</h3></div></div></div><p>Die Beschreibung der Bankerweiterung befindet sich derzeit noch
+   <title>3.2. Bankerweiterung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="next" href="ch03s03.html" title="3.3. Dokumentenvorlagen und verfügbare Variablen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.2. Bankerweiterung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s03.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.2. Bankerweiterung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.bank"></a>3.2. Bankerweiterung</h2></div></div></div><div class="sect2" title="3.2.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="features.bank.introduction"></a>3.2.1. Einführung</h3></div></div></div><p>Die Beschreibung der Bankerweiterung befindet sich derzeit noch
         im Wiki und soll von dort später hierhin übernommen werden:</p><p>
                <a class="ulink" href="http://redmine.kivitendo-premium.de/projects/forum/wiki/Bankerweiterung" target="_top">http://redmine.kivitendo-premium.de/projects/forum/wiki/Bankerweiterung</a>
             </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03.html">Zurück</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch03.html">Nach oben</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch03s03.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">Kapitel 3. Features und Funktionen&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Zum Anfang</a></td><td width="40%" align="right" valign="top">&nbsp;3.3. Dokumentenvorlagen und verfügbare Variablen</td></tr></table></div></body></html>
\ No newline at end of file
index 9c2e6cf..7c455f0 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.3. Dokumentenvorlagen und verfügbare Variablen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s02.html" title="3.2. Bankerweiterung"><link rel="next" href="ch03s04.html" title="3.4. Excel-Vorlagen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.3. Dokumentenvorlagen und verfügbare Variablen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s02.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.3. Dokumentenvorlagen und verfügbare Variablen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="dokumentenvorlagen-und-variablen"></a>3.3. Dokumentenvorlagen und verfügbare Variablen</h2></div></div></div><div class="sect2" title="3.3.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="dokumentenvorlagen-und-variablen.einf%C3%BChrung"></a>3.3.1. Einführung</h3></div></div></div><p>Dies ist eine Auflistung der Standard-Dokumentenvorlagen und
+   <title>3.3. Dokumentenvorlagen und verfügbare Variablen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s02.html" title="3.2. Bankerweiterung"><link rel="next" href="ch03s04.html" title="3.4. Excel-Vorlagen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.3. Dokumentenvorlagen und verfügbare Variablen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s02.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.3. Dokumentenvorlagen und verfügbare Variablen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="dokumentenvorlagen-und-variablen"></a>3.3. Dokumentenvorlagen und verfügbare Variablen</h2></div></div></div><div class="sect2" title="3.3.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="dokumentenvorlagen-und-variablen.einf%C3%BChrung"></a>3.3.1. Einführung</h3></div></div></div><p>Dies ist eine Auflistung der Standard-Dokumentenvorlagen und
         aller zur Bearbeitung verfügbaren Variablen. Eine Variable wird in
         einer Vorlage durch ihren Inhalt ersetzt, wenn sie in der Form
         <code class="function">&lt;%variablenname%&gt;</code> verwendet wird. Für
                      </span></dt><dd><p>Beschreibung der Lieferbedingung</p></dd><dt><span class="term">
                         <code class="varname">delivery_term.description_long</code>
                      </span></dt><dd><p>Langtext bzw. übersetzter Langtext der
-                Lieferbedingung</p></dd></dl></div></div></div><div class="sect2" title="3.3.8. Variablen in Rechnungen"><div class="titlepage"><div><div><h3 class="title"><a name="dokumentenvorlagen-und-variablen.invoice"></a>3.3.8. Variablen in Rechnungen</h3></div></div></div><div class="sect3" title="3.3.8.1. Allgemeine Variablen"><div class="titlepage"><div><div><h4 class="title"><a name="dokumentenvorlagen-und-variablen.invoice-allgemein"></a>3.3.8.1. Allgemeine Variablen</h4></div></div></div><div class="variablelist"><dl><dt><span class="term">
+                Lieferbedingung</p></dd></dl></div></div><div class="sect3" title="3.3.7.7. Informationen über abweichende Rechnungsadressen (nur Verkaufsbelege)"><div class="titlepage"><div><div><h4 class="title"><a name="dokumentenvorlagen-und-variablen.abweichende-rechnungsadresse"></a>3.3.7.7. Informationen über abweichende Rechnungsadressen (nur Verkaufsbelege)</h4></div></div></div><p>
+            Abweichende Rechnungsadressen gibt es nur in Verkaufsbelegen. Die entsprechenden Variablen sind nur dann mit Inhalt gefüllt,
+            wenn im Beleg eine abweichende Rechnungsadresse ausgewählt wurde. Ob eine Adresse überhaupt ausgewählt wurde, kann über die
+            Variable <code class="literal">billing_address_id</code> getestet werden, die die Datenbank-ID der abweichenden Rechnungsadresse enthält,
+            wenn eine ausgewählt ist.
+          </p><p>
+            Die Variablennamen starten alle mit dem Präfix <code class="literal">billing_address_</code> und heißen anschließend so, wie ihre Pendants
+            aus der Standard-Rechnungsadresse des Kunden. Beispiel: die Postleitzahl, die in der normalen Rechnungsadresse in
+            <code class="literal">zipcode</code> steht, steht für die abweichende Rechnungsadresse in <code class="literal">billing_address_zipcode</code>.
+          </p><p>
+            Die folgenden Variablen stehen so zur Verfügung: <code class="literal">billing_address_name</code>,
+            <code class="literal">billing_address_department_1</code>, <code class="literal">billing_address_department_2</code>,
+            <code class="literal">billing_address_contact</code>, <code class="literal">billing_address_street</code>,
+            <code class="literal">billing_address_zipcode</code>, <code class="literal">billing_address_city</code>, <code class="literal">billing_address_country</code>,
+            <code class="literal">billing_address_gln</code>, <code class="literal">billing_address_email</code>, <code class="literal">billing_address_phone</code> und
+            <code class="literal">billing_address_fax</code>.
+          </p></div></div><div class="sect2" title="3.3.8. Variablen in Rechnungen"><div class="titlepage"><div><div><h3 class="title"><a name="dokumentenvorlagen-und-variablen.invoice"></a>3.3.8. Variablen in Rechnungen</h3></div></div></div><div class="sect3" title="3.3.8.1. Allgemeine Variablen"><div class="titlepage"><div><div><h4 class="title"><a name="dokumentenvorlagen-und-variablen.invoice-allgemein"></a>3.3.8.1. Allgemeine Variablen</h4></div></div></div><div class="variablelist"><dl><dt><span class="term">
                         <code class="varname">creditremaining</code>
                      </span></dt><dd><p>Verbleibender Kredit</p></dd><dt><span class="term">
                         <code class="varname">currency</code>
                         <code class="varname">invdate</code>
                      </span></dt><dd><p>Rechnungsdatum</p></dd><dt><span class="term">
                         <code class="varname">invnumber</code>
-                     </span></dt><dd><p>Rechnungsnummer</p></dd></dl></div></div></div><div class="sect2" title="3.3.10. Variablen in anderen Vorlagen"><div class="titlepage"><div><div><h3 class="title"><a name="dokumentenvorlagen-und-variablen.andere-vorlagen"></a>3.3.10. Variablen in anderen Vorlagen</h3></div></div></div><div class="sect3" title="3.3.10.1. Einführung"><div class="titlepage"><div><div><h4 class="title"><a name="d0e5861"></a>3.3.10.1. Einführung</h4></div></div></div><p>Die Variablen in anderen Vorlagen sind ähnlich wie in der
+                     </span></dt><dd><p>Rechnungsnummer</p></dd></dl></div></div></div><div class="sect2" title="3.3.10. Variablen in anderen Vorlagen"><div class="titlepage"><div><div><h3 class="title"><a name="dokumentenvorlagen-und-variablen.andere-vorlagen"></a>3.3.10. Variablen in anderen Vorlagen</h3></div></div></div><div class="sect3" title="3.3.10.1. Einführung"><div class="titlepage"><div><div><h4 class="title"><a name="d0e6135"></a>3.3.10.1. Einführung</h4></div></div></div><p>Die Variablen in anderen Vorlagen sind ähnlich wie in der
           Rechnung. Allerdings heißen die Variablen, die mit
           <code class="varname">inv</code> beginnen, jetzt anders. Bei den Angeboten
           fangen sie mit <code class="varname">quo</code> für "quotation" an:
index 920bee1..19a2b73 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.4. Excel-Vorlagen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s03.html" title="3.3. Dokumentenvorlagen und verfügbare Variablen"><link rel="next" href="ch03s05.html" title="3.5. Mandantenkonfiguration Lager"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.4. Excel-Vorlagen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s03.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s05.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.4. Excel-Vorlagen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="excel-templates"></a>3.4. Excel-Vorlagen</h2></div></div></div><div class="sect2" title="3.4.1. Zusammenfassung"><div class="titlepage"><div><div><h3 class="title"><a name="excel-templates.summary"></a>3.4.1. Zusammenfassung</h3></div></div></div><p>Dieses Dokument beschreibt den Mechanismus, mit dem
+   <title>3.4. Excel-Vorlagen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s03.html" title="3.3. Dokumentenvorlagen und verfügbare Variablen"><link rel="next" href="ch03s05.html" title="3.5. Mandantenkonfiguration Lager"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.4. Excel-Vorlagen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s03.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s05.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.4. Excel-Vorlagen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="excel-templates"></a>3.4. Excel-Vorlagen</h2></div></div></div><div class="sect2" title="3.4.1. Zusammenfassung"><div class="titlepage"><div><div><h3 class="title"><a name="excel-templates.summary"></a>3.4.1. Zusammenfassung</h3></div></div></div><p>Dieses Dokument beschreibt den Mechanismus, mit dem
         Exceltemplates abgearbeitet werden, und die Einschränkungen, die damit
         einhergehen.</p></div><div class="sect2" title="3.4.2. Bedienung"><div class="titlepage"><div><div><h3 class="title"><a name="excel-templates.usage"></a>3.4.2. Bedienung</h3></div></div></div><p>Der Excel Mechanismus muss in der Konfigurationsdatei aktiviert
         werden. Die Konfigurationsoption heißt <code class="varname">excel_templates =
index 79c5177..a623a98 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.5. Mandantenkonfiguration Lager</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s04.html" title="3.4. Excel-Vorlagen"><link rel="next" href="ch03s06.html" title="3.6. Schweizer Kontenpläne"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.5. Mandantenkonfiguration Lager</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s04.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s06.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.5. Mandantenkonfiguration Lager"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.warehouse"></a>3.5. Mandantenkonfiguration Lager</h2></div></div></div><p>Die Lagerverwaltung in kivitendo funktioniert standardmässig wie
+   <title>3.5. Mandantenkonfiguration Lager</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s04.html" title="3.4. Excel-Vorlagen"><link rel="next" href="ch03s06.html" title="3.6. Schweizer Kontenpläne"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.5. Mandantenkonfiguration Lager</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s04.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s06.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.5. Mandantenkonfiguration Lager"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.warehouse"></a>3.5. Mandantenkonfiguration Lager</h2></div></div></div><p>Die Lagerverwaltung in kivitendo funktioniert standardmässig wie
       folgt: Wird ein Lager mit einem Lagerplatz angelegt, so gibt es die
       Möglichkeit hier über den Menüpunkt Lager entsprechende Warenbewegungen
       durchzuführen. Ferner kann jede Position eines Lieferscheins ein-, bzw.
index ce61002..5444a32 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.6. Schweizer Kontenpläne</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s05.html" title="3.5. Mandantenkonfiguration Lager"><link rel="next" href="ch03s07.html" title="3.7. Artikelklassifizierung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.6. Schweizer Kontenpläne</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s05.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s07.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.6. Schweizer Kontenpläne"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.swiss-charts-of-accounts"></a>3.6. Schweizer Kontenpläne</h2></div></div></div><p>Seit der Version 3.5 stehen in kivitendo 3 Kontenpläne für den
+   <title>3.6. Schweizer Kontenpläne</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s05.html" title="3.5. Mandantenkonfiguration Lager"><link rel="next" href="ch03s07.html" title="3.7. Artikelklassifizierung"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.6. Schweizer Kontenpläne</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s05.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s07.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.6. Schweizer Kontenpläne"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.swiss-charts-of-accounts"></a>3.6. Schweizer Kontenpläne</h2></div></div></div><p>Seit der Version 3.5 stehen in kivitendo 3 Kontenpläne für den
       Einsatz in der Schweiz zur Verfügung, einer für Firmen und
       Organisationen, die nicht mehrwertsteuerpflichtig sind, einer für
       Firmen, die mehrwertsteuerpflichtig sind und einer speziell für
index 995ee44..32ef9e4 100644 (file)
@@ -1,15 +1,15 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.7. Artikelklassifizierung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s06.html" title="3.6. Schweizer Kontenpläne"><link rel="next" href="ch03s08.html" title="3.8. Dateiverwaltung (Mini-DMS)"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.7. Artikelklassifizierung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s06.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s08.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.7. Artikelklassifizierung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.part_classification"></a>3.7. Artikelklassifizierung</h2></div></div></div><div class="sect2" title="3.7.1. Übersicht"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6543"></a>3.7.1. Übersicht</h3></div></div></div><p>Die Klassifizierung von Artikeln dient einer weiteren
+   <title>3.7. Artikelklassifizierung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s06.html" title="3.6. Schweizer Kontenpläne"><link rel="next" href="ch03s08.html" title="3.8. Dateiverwaltung (Mini-DMS)"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.7. Artikelklassifizierung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s06.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s08.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.7. Artikelklassifizierung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.part_classification"></a>3.7. Artikelklassifizierung</h2></div></div></div><div class="sect2" title="3.7.1. Übersicht"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6817"></a>3.7.1. Übersicht</h3></div></div></div><p>Die Klassifizierung von Artikeln dient einer weiteren
         Gliederung, um zum Beispiel den Einkauf vom Verkauf zu trennen,
         gekennzeichnet durch eine Beschreibung (z.B. "Einkauf") und ein Kürzel
         (z.B. "E"). Für jede Klassifizierung besteht eine Beschreibung und
         eine Abkürzung die normalerweise aus einem Zeichen besteht, kann aber
         auf mehrere Zeichen erweitert werden, falls zur Unterscheidung
-        notwendig. Sinnvoll sind jedoch nur maximal 2 Zeichen.</p></div><div class="sect2" title="3.7.2. Basisklassifizierung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6548"></a>3.7.2. Basisklassifizierung</h3></div></div></div><p>Als Basisklassifizierungen gibt es</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Einkauf</p></li><li class="listitem"><p>Verkauf</p></li><li class="listitem"><p>Handelsware</p></li><li class="listitem"><p>Produktion</p></li><li class="listitem"><p>- keine - (diese wird bei einer Aktualisierung für alle
+        notwendig. Sinnvoll sind jedoch nur maximal 2 Zeichen.</p></div><div class="sect2" title="3.7.2. Basisklassifizierung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6822"></a>3.7.2. Basisklassifizierung</h3></div></div></div><p>Als Basisklassifizierungen gibt es</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Einkauf</p></li><li class="listitem"><p>Verkauf</p></li><li class="listitem"><p>Handelsware</p></li><li class="listitem"><p>Produktion</p></li><li class="listitem"><p>- keine - (diese wird bei einer Aktualisierung für alle
             existierenden Artikel verwendet und ist gültig für Verkauf und
             Einkauf)</p></li></ul></div><p>Es können weitere Klassifizierungen angelegt werden. So kann es
-        z.B. für separat auszuweisende Artikel folgende Klassen geben:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Lieferung (Logistik, Transport) mit Kürzel L</p></li><li class="listitem"><p>Material (Verpackungsmaterial) mit Kürzel M</p></li></ul></div></div><div class="sect2" title="3.7.3. Attribute"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6578"></a>3.7.3. Attribute</h3></div></div></div><p>Bisher haben die Klassifizierungen folgende Attribute, die auch
+        z.B. für separat auszuweisende Artikel folgende Klassen geben:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Lieferung (Logistik, Transport) mit Kürzel L</p></li><li class="listitem"><p>Material (Verpackungsmaterial) mit Kürzel M</p></li></ul></div></div><div class="sect2" title="3.7.3. Attribute"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6852"></a>3.7.3. Attribute</h3></div></div></div><p>Bisher haben die Klassifizierungen folgende Attribute, die auch
         alle gleichzeitg gültig sein können</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>gültig für Verkauf - dieser Artikel kann im Verkauf genutzt
             werden</p></li><li class="listitem"><p>gültig für Einkauf - dieser Artikel kann im Einkauf genutzt
             werden</p></li><li class="listitem"><p>separat ausweisen - hierzu gibt es zur Dokumentengenerierung
@@ -19,7 +19,7 @@
         pro separat auszuweisenden Klassifizierungen die Variable<span class="bold"><strong>&lt; %separate_X_subtotal%&gt;</strong></span>, wobei X das
         Kürzel der Klassifizierung ist.</p><p>Im obigen Beispiel wäre das für Lieferkosten <span class="bold"><strong>&lt;%separate_L_subtotal%&gt;</strong></span> und für
         Verpackungsmaterial <span class="bold"><strong>
-        &lt;%separate_M_subtotal%&gt;</strong></span>.</p></div><div class="sect2" title="3.7.4. Zwei-Zeichen Abkürzung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6609"></a>3.7.4. Zwei-Zeichen Abkürzung</h3></div></div></div><p>Der Typ des Artikels und die Klassifizierung werden durch zwei
+        &lt;%separate_M_subtotal%&gt;</strong></span>.</p></div><div class="sect2" title="3.7.4. Zwei-Zeichen Abkürzung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6883"></a>3.7.4. Zwei-Zeichen Abkürzung</h3></div></div></div><p>Der Typ des Artikels und die Klassifizierung werden durch zwei
         Buchstaben dargestellt. Der erste Buchstabe ist eine Lokalisierung des
         Artikel-Typs ('P','A','S'), deutsch 'W', 'E', und 'D' für Ware
         Erzeugnis oder Dienstleistung und ggf. weiterer Typen.</p><p>Der zweite Buchstabe (und ggf. auch ein dritter, falls nötig)
index 390d66e..17a969e 100644 (file)
@@ -1,10 +1,10 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.8. Dateiverwaltung (Mini-DMS)</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s07.html" title="3.7. Artikelklassifizierung"><link rel="next" href="ch03s09.html" title="3.9. Webshop-Api"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.8. Dateiverwaltung (Mini-DMS)</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s07.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s09.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.8. Dateiverwaltung (Mini-DMS)"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.file_managment"></a>3.8. Dateiverwaltung (Mini-DMS)</h2></div></div></div><div class="sect2" title="3.8.1. Übersicht"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6621"></a>3.8.1. Übersicht</h3></div></div></div><p>Parallel zum alten WebDAV gibt es ein Datei-Management-System,
+   <title>3.8. Dateiverwaltung (Mini-DMS)</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s07.html" title="3.7. Artikelklassifizierung"><link rel="next" href="ch03s09.html" title="3.9. Webshop-Api"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.8. Dateiverwaltung (Mini-DMS)</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s07.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s09.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.8. Dateiverwaltung (Mini-DMS)"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.file_managment"></a>3.8. Dateiverwaltung (Mini-DMS)</h2></div></div></div><div class="sect2" title="3.8.1. Übersicht"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6895"></a>3.8.1. Übersicht</h3></div></div></div><p>Parallel zum alten WebDAV gibt es ein Datei-Management-System,
         das Dateien verschiedenen Typs verwaltet. Dies können</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>aus ERP-Daten per LaTeX Template erzeugte
             PDF-Dokumente,</p></li><li class="listitem"><p>zu bestimmten ERP-Daten gehörende Anhangdateien
             unterschiedlichen Formats,</p></li><li class="listitem"><p>per Scanner eingelesene PDF-Dateien,</p></li><li class="listitem"><p>per E-Mail empfangene Dateianhänge unterschiedlichen
-            Formats,</p></li><li class="listitem"><p>sowie speziel für Artikel hochgeladene Bilder sein.</p></li></ol></div><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Overview.png"></div></div></div><div class="sect2" title="3.8.2. Struktur"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6648"></a>3.8.2. Struktur</h3></div></div></div><p>Über eine vom Speichermedium unabhängige Zwischenschicht werden
+            Formats,</p></li><li class="listitem"><p>sowie speziel für Artikel hochgeladene Bilder sein.</p></li></ol></div><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Overview.png"></div></div></div><div class="sect2" title="3.8.2. Struktur"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6922"></a>3.8.2. Struktur</h3></div></div></div><p>Über eine vom Speichermedium unabhängige Zwischenschicht werden
         die Dateien und ihre Versionen in der Datenbank verwaltet. Darunter
         können verschiedene Implementierungen (Backends) gleichzeitig
         existieren:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Dateisystem</p></li><li class="listitem"><p>WebDAV</p></li><li class="listitem"><p>Schnittstelle zu externen
@@ -23,7 +23,7 @@
         für "attachment" und "image" nur die Quelle "uploaded". Für "document"
         gibt es auf jeden Fall die Quelle "created". Die Quellen "scanner" und
         "email" müssen derzeit in der Datenbank konfiguriert werden (siehe
-        <a class="xref" href="ch03s08.html#file_management.dbconfig" title="3.8.4.2. Datenbank-Konfigurierung">Datenbank-Konfigurierung</a>).</p></div><div class="sect2" title="3.8.3. Anwendung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6700"></a>3.8.3. Anwendung</h3></div></div></div><p>Die Daten werden bei den ERP-Objekten als extra Reiter
+        <a class="xref" href="ch03s08.html#file_management.dbconfig" title="3.8.4.2. Datenbank-Konfigurierung">Datenbank-Konfigurierung</a>).</p></div><div class="sect2" title="3.8.3. Anwendung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6974"></a>3.8.3. Anwendung</h3></div></div></div><p>Die Daten werden bei den ERP-Objekten als extra Reiter
         dargestellt. Eine Verkaufsrechnung z.B. hat die Reiter "Dokumente" und
         "Dateianhänge".</p><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Anhaenge.png"></div></div><p>Bei den Dateianhängen wird immer nur die aktuelle Version einer
         Datei angezeigt. Wird eine Datei mit gleichem Namen hochgeladen, so
         so sind diese z.B. bei Einkaufsrechnungen sichtbar:</p><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Dokumente-Scanner.png"></div></div><p>Statt des Löschens wird hier die Datei zurück zur Quelle
         verschoben. Somit kann die Datei anschließend an ein anderes
         ERP-Objekt angehängt werden.</p><p>Derzeit sind "Titel" und "Beschreibung" noch nicht genutzt. Sie
-        sind bisher nur bei Bildern relevant.</p></div><div class="sect2" title="3.8.4. Konfigurierung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6743"></a>3.8.4. Konfigurierung</h3></div></div></div><div class="sect3" title="3.8.4.1. Mandantenkonfiguration"><div class="titlepage"><div><div><h4 class="title"><a name="file_management.clientconfig"></a>3.8.4.1. Mandantenkonfiguration</h4></div></div></div><div class="sect4" title="3.8.4.1.1. Reiter &#34;Features&#34;"><div class="titlepage"><div><div><h5 class="title"><a name="d0e6749"></a>3.8.4.1.1. Reiter "Features"</h5></div></div></div><p>Unter dem Reiter <span class="bold"><strong>Features</strong></span>
+        sind bisher nur bei Bildern relevant.</p></div><div class="sect2" title="3.8.4. Konfigurierung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7017"></a>3.8.4. Konfigurierung</h3></div></div></div><div class="sect3" title="3.8.4.1. Mandantenkonfiguration"><div class="titlepage"><div><div><h4 class="title"><a name="file_management.clientconfig"></a>3.8.4.1. Mandantenkonfiguration</h4></div></div></div><div class="sect4" title="3.8.4.1.1. Reiter &#34;Features&#34;"><div class="titlepage"><div><div><h5 class="title"><a name="d0e7023"></a>3.8.4.1.1. Reiter "Features"</h5></div></div></div><p>Unter dem Reiter <span class="bold"><strong>Features</strong></span>
             im Abschnitt Dateimanagement ist neben dem "alten" WebDAV das
             Dateimangement generell zu- und abschaltbar, sowie die Zuordnung
             der Dateitypen zu Backends. Die Löschbarkeit von Dateien, sowie
             die maximale Uploadgröße sind Backend-unabhängig</p><div class="screenshot"><div class="mediaobject"><img src="images/DMS-ClientConfig.png"></div></div><p>Die einzelnen Backends sind einzeln einschaltbar.
             Spezifische Backend-Konfigurierungen sind hier noch
-            ergänzbar.</p></div><div class="sect4" title="3.8.4.1.2. Reiter &#34;Allgemeine Dokumentenanhänge&#34;"><div class="titlepage"><div><div><h5 class="title"><a name="d0e6765"></a>3.8.4.1.2. Reiter "Allgemeine Dokumentenanhänge"</h5></div></div></div><p>Unter dem Reiter <span class="bold"><strong>Allgemeine
+            ergänzbar.</p></div><div class="sect4" title="3.8.4.1.2. Reiter &#34;Allgemeine Dokumentenanhänge&#34;"><div class="titlepage"><div><div><h5 class="title"><a name="d0e7039"></a>3.8.4.1.2. Reiter "Allgemeine Dokumentenanhänge"</h5></div></div></div><p>Unter dem Reiter <span class="bold"><strong>Allgemeine
             Dokumentenanhänge</strong></span> kann für alle ERP-Dokumente (
             Angebote, Aufträge, Lieferscheine, Rechnungen im Verkauf und
             Einkauf ) allgemeingültige Anhänge hochgeladen werden.</p><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Allgemeine-Dokumentenanhaenge.png"></div></div><p>Diese Anhänge werden beim Generieren von PDF-Dateien an die
index fbae8ef..3bb78a3 100644 (file)
@@ -1,13 +1,13 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.9. Webshop-Api</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s08.html" title="3.8. Dateiverwaltung (Mini-DMS)"><link rel="next" href="ch03s10.html" title="3.10. ZUGFeRD Rechnungen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.9. Webshop-Api</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s08.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s10.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.9. Webshop-Api"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e6799"></a>3.9. Webshop-Api</h2></div></div></div><p>Das Shopmodul bietet die Möglichkeit Onlineshopartikel und
+   <title>3.9. Webshop-Api</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s08.html" title="3.8. Dateiverwaltung (Mini-DMS)"><link rel="next" href="ch03s10.html" title="3.10. ZUGFeRD Rechnungen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.9. Webshop-Api</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s08.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s10.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.9. Webshop-Api"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e7073"></a>3.9. Webshop-Api</h2></div></div></div><p>Das Shopmodul bietet die Möglichkeit Onlineshopartikel und
       Onlineshopbestellungen zu verwalten und zu bearbeiten.</p><p>Es ist Multishopfähig, d.h. Artikel können mehreren oder
       unterschiedlichen Shops zugeordnet werden. Bestellungen können aus
       mehreren Shops geholt werden.</p><p>Zur Zeit bietet das Modul nur einen Connector zur REST-Api von
       Shopware. Weitere Connectoren können dazu programmiert und eingerichtet
-      werden.</p><div class="sect2" title="3.9.1. Rechte für die Webshopapi"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6808"></a>3.9.1. Rechte für die Webshopapi</h3></div></div></div><p>In der Administration können folgende Rechte vergeben
-        werden</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Webshopartikel anlegen und bearbeiten</p></li><li class="listitem"><p>Shopbestellungen holen und bearbeiten</p></li><li class="listitem"><p>Shop anlegen und bearbeiten</p></li></ul></div></div><div class="sect2" title="3.9.2. Konfiguration"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6823"></a>3.9.2. Konfiguration</h3></div></div></div><p>Unter System-&gt;Webshops können Shops angelegt und konfiguriert
-        werden</p><div class="mediaobject"><img src="images/Shop_Listing.png"></div></div><div class="sect2" title="3.9.3. Webshopartikel"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6831"></a>3.9.3. Webshopartikel</h3></div></div></div><div class="sect3" title="3.9.3.1. Shopvariablenreiter in Artikelstammdaten"><div class="titlepage"><div><div><h4 class="title"><a name="d0e6834"></a>3.9.3.1. Shopvariablenreiter in Artikelstammdaten</h4></div></div></div><p>Mit dem Recht "Shopartikel anlegen und bearbeiten" und des
+      werden.</p><div class="sect2" title="3.9.1. Rechte für die Webshopapi"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7082"></a>3.9.1. Rechte für die Webshopapi</h3></div></div></div><p>In der Administration können folgende Rechte vergeben
+        werden</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Webshopartikel anlegen und bearbeiten</p></li><li class="listitem"><p>Shopbestellungen holen und bearbeiten</p></li><li class="listitem"><p>Shop anlegen und bearbeiten</p></li></ul></div></div><div class="sect2" title="3.9.2. Konfiguration"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7097"></a>3.9.2. Konfiguration</h3></div></div></div><p>Unter System-&gt;Webshops können Shops angelegt und konfiguriert
+        werden</p><div class="mediaobject"><img src="images/Shop_Listing.png"></div></div><div class="sect2" title="3.9.3. Webshopartikel"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7105"></a>3.9.3. Webshopartikel</h3></div></div></div><div class="sect3" title="3.9.3.1. Shopvariablenreiter in Artikelstammdaten"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7108"></a>3.9.3.1. Shopvariablenreiter in Artikelstammdaten</h4></div></div></div><p>Mit dem Recht "Shopartikel anlegen und bearbeiten" und des
           Markers <span class="bold"><strong>"Shopartikel" in den Basisdaten
           </strong></span>zeigt sich der Reiter "Shopvariablen" in den
           Artikelstammdaten. Hier können jetzt die Artikel mit
           Stelle können auch beliebig viele Bilder dem Shopartikel zugeordnet
           werden. Artikelbilder gelten für alle Shops.</p><div class="mediaobject"><img src="images/Shop_Artikel.png"></div><p>Die Artikelgruppen werden direkt vom Shopsystem geholt somit
           ist es möglich einen Artikel auch mehreren Gruppen
-          zuzuordenen</p></div><div class="sect3" title="3.9.3.2. Shopartikelliste"><div class="titlepage"><div><div><h4 class="title"><a name="d0e6847"></a>3.9.3.2. Shopartikelliste</h4></div></div></div><p>Unter dem Menu Webshop-&gt;Webshop Artikel hat man nochmal
+          zuzuordenen</p></div><div class="sect3" title="3.9.3.2. Shopartikelliste"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7121"></a>3.9.3.2. Shopartikelliste</h4></div></div></div><p>Unter dem Menu Webshop-&gt;Webshop Artikel hat man nochmal
           eine Gesamtübersicht. Von hier aus ist es möglich Artikel im Stapel
           unter verschiedenen Kriterien &lt;alles&gt;&lt;nur Preis&gt;&lt;nur
           Bestand&gt;&lt;Preis und Bestand&gt; an die jeweiligen Shops
-          hochzuladen.</p><div class="mediaobject"><img src="images/Shop_Artikel_Listing.png"></div></div></div><div class="sect2" title="3.9.4. Bestellimport"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6855"></a>3.9.4. Bestellimport</h3></div></div></div><p>Unter dem Menupunkt Webshop-&gt;Webshop Import öffnet sich die
+          hochzuladen.</p><div class="mediaobject"><img src="images/Shop_Artikel_Listing.png"></div></div></div><div class="sect2" title="3.9.4. Bestellimport"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7129"></a>3.9.4. Bestellimport</h3></div></div></div><p>Unter dem Menupunkt Webshop-&gt;Webshop Import öffnet sich die
         Bestellimportsliste. Hier ist sind Möglichkeiten gegeben Neue
         Bestellungen vom Shop abzuholen, geholte Bestellungen im Stapel oder
         einzeln als Auftrag zu transferieren. Die Liste kann nach
@@ -52,7 +52,7 @@
             auch der Grund für die Auftragssperre sein.</p></li><li class="listitem"><p>Die Buttons "Auftrag erstellen" und "Kunde mit
             Rechnungsadresse überschreiben" zeigen sich erst, wenn ein Kunde
             aus dem Listing ausgewählt ist.</p></li><li class="listitem"><p>Es ist aber möglich die Shopbestellung zu löschen.</p></li><li class="listitem"><p>Ist eine Bestellung schon übernommen, zeigen sich an dieser
-            Stelle, die dazugehörigen Belegverknüpfungen.</p></li></ul></div></div><div class="sect2" title="3.9.5. Mapping der Daten"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6908"></a>3.9.5. Mapping der Daten</h3></div></div></div><p>Das Mapping der kivitendo Daten mit den Shopdaten geschieht in
+            Stelle, die dazugehörigen Belegverknüpfungen.</p></li></ul></div></div><div class="sect2" title="3.9.5. Mapping der Daten"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7182"></a>3.9.5. Mapping der Daten</h3></div></div></div><p>Das Mapping der kivitendo Daten mit den Shopdaten geschieht in
         der Datei SL/ShopConnector/&lt;SHOPCONNECTORNAME&gt;.pm
         z.B.:SL/ShopConnector/Shopware.pm</p><p>In dieser Datei gibt es einen Bereich wo die Bestellpostionen,
         die Bestellkopfdaten und die Artikeldaten gemapt werden. In dieser
index f399a45..ef0de2e 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.10. ZUGFeRD Rechnungen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s09.html" title="3.9. Webshop-Api"><link rel="next" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.10. ZUGFeRD Rechnungen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s09.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.10. ZUGFeRD Rechnungen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.zugferd"></a>3.10. ZUGFeRD Rechnungen</h2></div></div></div><div class="sect2" title="3.10.1. Vorbedingung"><div class="titlepage"><div><div><h3 class="title"><a name="features.zugferd.preamble"></a>3.10.1. Vorbedingung</h3></div></div></div><p>
+   <title>3.10. ZUGFeRD Rechnungen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s09.html" title="3.9. Webshop-Api"><link rel="next" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.10. ZUGFeRD Rechnungen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s09.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.10. ZUGFeRD Rechnungen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.zugferd"></a>3.10. ZUGFeRD Rechnungen</h2></div></div></div><div class="sect2" title="3.10.1. Vorbedingung"><div class="titlepage"><div><div><h3 class="title"><a name="features.zugferd.preamble"></a>3.10.1. Vorbedingung</h3></div></div></div><p>
           Für die Erstellung von ZUGFeRD PDFs wird TexLive2018 oder höher benötigt.
          </p><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left">Anmerkung</th></tr><tr><td align="left" valign="top"><p>
           Wer kein TexLive2018 oder höher installieren kann, kann eine lokale Umgebung nur für kivitendo wie folgt erzeugen:
                        standardisiert und ermöglicht so den Austausch zwischen
                        den verschiedenen Softwareprodukten. Kivitendo setzt mit der
                        Version 3.5.6 den ZUGFeRD 2.1 Standard um.</p><p>Weiter Details zu ZUGFeRD sind unter diesem Link zu finden:
-                       <a class="ulink" href="" target="_top">https://www.ferd-net.de/standards/was-ist-zugferd/index.html</a>
+                       <a class="ulink" href="https://www.ferd-net.de/standards/was-ist-zugferd/index.html" target="_top">https://www.ferd-net.de/standards/was-ist-zugferd/index.html</a>
       
             </p></div><div class="sect2" title="3.10.3. Erstellen von ZUGFeRD Rechnungen in Kivitendo"><div class="titlepage"><div><div><h3 class="title"><a name="features.zugferd.create_zugferd_bills"></a>3.10.3. Erstellen von ZUGFeRD Rechnungen in Kivitendo</h3></div></div></div><p>Für die Erstellung von ZUGFeRD Rechnungen bedarf es in
                        kivitendo zwei Dinge:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>Die Erstellung muss in der Mandantenkonfiguration
                                        aktiviert sein</p></li><li class="listitem"><p>Beim mindestens einem Bankkonto muss die Option
-                                       „Nutzung von ZUGFeRD“ aktiviert sein</p></li></ol></div><div class="sect3" title="3.10.3.1. Mandantenkonfiguration"><div class="titlepage"><div><div><h4 class="title"><a name="d0e6955"></a>3.10.3.1. Mandantenkonfiguration</h4></div></div></div><p>Die Einstellung für die Erstellung von ZUGFeRD Rechnungen
+                                       „Nutzung von ZUGFeRD“ aktiviert sein</p></li></ol></div><div class="sect3" title="3.10.3.1. Mandantenkonfiguration"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7229"></a>3.10.3.1. Mandantenkonfiguration</h4></div></div></div><p>Die Einstellung für die Erstellung von ZUGFeRD Rechnungen
                                erfolgt unter „System“ → „Mandatenkonfiguration“ → „Features“.
                                Im Abschnitt „Einkauf und Verkauf“ finden Sie die Einstellung
                                „Verkaufsrechnungen mit ZUGFeRD-Daten erzeugen“.
                                Hier besteht die Auswahl zwischen:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>ZUGFeRD-Rechnungen erzeugen</p></li><li class="listitem"><p>ZUGFeRD-Rechnungen im Testmodus erzeugen</p></li><li class="listitem"><p>Keine ZUGFeRD Rechnungen erzeugen</p></li></ul></div><p>Rechnungen die als PDF erzeugt werden, werden je nach
-                               Einstellung nun im ZUGFeRD Format ausgegeben.</p></div><div class="sect3" title="3.10.3.2. Konfiguration der Bankkonten"><div class="titlepage"><div><div><h4 class="title"><a name="d0e6972"></a>3.10.3.2. Konfiguration der Bankkonten</h4></div></div></div><p>Unter „System → Bankkonten“ muss bei mindestens einem
+                               Einstellung nun im ZUGFeRD Format ausgegeben.</p></div><div class="sect3" title="3.10.3.2. Konfiguration der Bankkonten"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7246"></a>3.10.3.2. Konfiguration der Bankkonten</h4></div></div></div><p>Unter „System → Bankkonten“ muss bei mindestens einem
                                Bankkonto die Option „Nutzung mit ZUGFeRD“ auf „Ja“ gestellt
                                werden.</p></div></div><div class="sect2" title="3.10.4. Einlesen von ZUGFeRD Rechnungen in Kivitendo"><div class="titlepage"><div><div><h3 class="title"><a name="features.zugferd.read_zugferd_bills"></a>3.10.4. Einlesen von ZUGFeRD Rechnungen in Kivitendo</h3></div></div></div><p>Es lassen sich auch Rechnungen von Kreditoren, die im
                        ZUGFeRD Format erstellt wurden, nach Kivitendo importieren.
index 3664f74..6abd36c 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>Kapitel 4. Entwicklerdokumentation</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="prev" href="ch03s10.html" title="3.10. ZUGFeRD Rechnungen"><link rel="next" href="ch04s02.html" title="4.2. Entwicklung unter FastCGI"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 4. Entwicklerdokumentation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s10.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 4. Entwicklerdokumentation"><div class="titlepage"><div><div><h2 class="title"><a name="d0e6991"></a>Kapitel 4. Entwicklerdokumentation</h2></div></div></div><div class="sect1" title="4.1. Globale Variablen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.globals"></a>4.1. Globale Variablen</h2></div></div></div><div class="sect2" title="4.1.1. Wie sehen globale Variablen in Perl aus?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6997"></a>4.1.1. Wie sehen globale Variablen in Perl aus?</h3></div></div></div><p>Globale Variablen liegen in einem speziellen namespace namens
+   <title>Kapitel 4. Entwicklerdokumentation</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="prev" href="ch03s10.html" title="3.10. ZUGFeRD Rechnungen"><link rel="next" href="ch04s02.html" title="4.2. Entwicklung unter FastCGI"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 4. Entwicklerdokumentation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s10.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 4. Entwicklerdokumentation"><div class="titlepage"><div><div><h2 class="title"><a name="d0e7265"></a>Kapitel 4. Entwicklerdokumentation</h2></div></div></div><div class="sect1" title="4.1. Globale Variablen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.globals"></a>4.1. Globale Variablen</h2></div></div></div><div class="sect2" title="4.1.1. Wie sehen globale Variablen in Perl aus?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7271"></a>4.1.1. Wie sehen globale Variablen in Perl aus?</h3></div></div></div><p>Globale Variablen liegen in einem speziellen namespace namens
         "main", der von überall erreichbar ist. Darüber hinaus sind bareword
         globs global und die meisten speziellen Variablen sind...
         speziell.</p><p>Daraus ergeben sich folgende Formen:</p><div class="variablelist"><dl><dt><span class="term">
@@ -25,7 +25,7 @@
               <code class="varname">$PACKAGE::form</code>.</p></dd><dt><span class="term">
                      <code class="literal">local $form</code>
                   </span></dt><dd><p>Alle Änderungen an <code class="varname">$form</code> werden am Ende
-              des scopes zurückgesetzt</p></dd></dl></div></div><div class="sect2" title="4.1.2. Warum sind globale Variablen ein Problem?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7098"></a>4.1.2. Warum sind globale Variablen ein Problem?</h3></div></div></div><p>Das erste Problem ist <span class="productname">FCGI</span>™.</p><p>
+              des scopes zurückgesetzt</p></dd></dl></div></div><div class="sect2" title="4.1.2. Warum sind globale Variablen ein Problem?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7372"></a>4.1.2. Warum sind globale Variablen ein Problem?</h3></div></div></div><p>Das erste Problem ist <span class="productname">FCGI</span>™.</p><p>
                <span class="productname">SQL-Ledger</span>™ hat fast alles im globalen
         namespace abgelegt, und erwartet, dass es da auch wiederzufinden ist.
         Unter <span class="productname">FCGI</span>™ müssen diese Sachen aber wieder
@@ -39,7 +39,7 @@
         dies hat, seit der Einführung, u.a. schon so manche langwierige
         Bug-Suche verkürzt. Da globale Variablen aber implizit mit Package
         angegeben werden, werden die nicht geprüft, und somit kann sich
-        schnell ein Tippfehler einschleichen.</p></div><div class="sect2" title="4.1.3. Kanonische globale Variablen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7131"></a>4.1.3. Kanonische globale Variablen</h3></div></div></div><p>Um dieses Problem im Griff zu halten gibt es einige wenige
+        schnell ein Tippfehler einschleichen.</p></div><div class="sect2" title="4.1.3. Kanonische globale Variablen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7405"></a>4.1.3. Kanonische globale Variablen</h3></div></div></div><p>Um dieses Problem im Griff zu halten gibt es einige wenige
         globale Variablen, die kanonisch sind, d.h. sie haben bestimmte
         vorgegebenen Eigenschaften, und alles andere sollte anderweitig
         umhergereicht werden.</p><p>Diese Variablen sind im Moment die folgenden neun:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
@@ -62,7 +62,7 @@
                      <code class="varname">$::request</code>
                   </p></li></ul></div><p>Damit diese nicht erneut als Müllhalde missbraucht werden, im
         Folgenden eine kurze Erläuterung der bestimmten vorgegebenen
-        Eigenschaften (Konventionen):</p><div class="sect3" title="4.1.3.1. $::form"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7195"></a>4.1.3.1. $::form</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Ist ein Objekt der Klasse
+        Eigenschaften (Konventionen):</p><div class="sect3" title="4.1.3.1. $::form"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7469"></a>4.1.3.1. $::form</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Ist ein Objekt der Klasse
               "<code class="classname">Form</code>"</p></li><li class="listitem"><p>Wird nach jedem Request gelöscht</p></li><li class="listitem"><p>Muss auch in Tests und Konsolenscripts vorhanden
               sein.</p></li><li class="listitem"><p>Enthält am Anfang eines Requests die Requestparameter vom
               User</p></li><li class="listitem"><p>Kann zwar intern über Requestgrenzen ein Datenbankhandle
   push @{ $form-&gt;{TEMPLATE_ARRAYS}{number} },          $form-&gt;{"partnumber_$i"};
   push @{ $form-&gt;{TEMPLATE_ARRAYS}{description} },     $form-&gt;{"description_$i"};
   # ...
-}</pre></div><div class="sect3" title="4.1.3.2. %::myconfig"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7279"></a>4.1.3.2. %::myconfig</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Das einzige Hash unter den globalen Variablen</p></li><li class="listitem"><p>Wird spätestens benötigt wenn auf die Datenbank
+}</pre></div><div class="sect3" title="4.1.3.2. %::myconfig"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7553"></a>4.1.3.2. %::myconfig</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Das einzige Hash unter den globalen Variablen</p></li><li class="listitem"><p>Wird spätestens benötigt wenn auf die Datenbank
               zugegriffen wird</p></li><li class="listitem"><p>Wird bei jedem Request neu erstellt.</p></li><li class="listitem"><p>Enthält die Userdaten des aktuellen Logins</p></li><li class="listitem"><p>Sollte nicht ohne Filterung irgendwo gedumpt werden oder
               extern serialisiert werden, weil da auch der Datenbankzugriff
               für diesen user drinsteht.</p></li><li class="listitem"><p>Enthält unter anderem Datumsformat dateformat und
           überwiegend die Daten, die sich unter <span class="guimenu">Programm</span>
           -&gt; <span class="guimenuitem">Einstellungen</span> befinden, bzw. die
           Informationen über den Benutzer die über die
-          Administrator-Schnittstelle eingegeben wurden.</p></div><div class="sect3" title="4.1.3.3. $::locale"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7318"></a>4.1.3.3. $::locale</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "Locale"</p></li><li class="listitem"><p>Wird pro Request erstellt</p></li><li class="listitem"><p>Muss auch für Tests und Scripte immer verfügbar
+          Administrator-Schnittstelle eingegeben wurden.</p></div><div class="sect3" title="4.1.3.3. $::locale"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7592"></a>4.1.3.3. $::locale</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "Locale"</p></li><li class="listitem"><p>Wird pro Request erstellt</p></li><li class="listitem"><p>Muss auch für Tests und Scripte immer verfügbar
               sein.</p></li><li class="listitem"><p>Cached intern über Requestgrenzen hinweg benutzte
               Locales</p></li></ul></div><p>Lokalisierung für den aktuellen User. Alle Übersetzungen,
-          Zahlen- und Datumsformatierungen laufen über dieses Objekt.</p></div><div class="sect3" title="4.1.3.4. $::lxdebug"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7336"></a>4.1.3.4. $::lxdebug</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "LXDebug"</p></li><li class="listitem"><p>Wird global gecached</p></li><li class="listitem"><p>Muss immer verfügbar sein, in nahezu allen
+          Zahlen- und Datumsformatierungen laufen über dieses Objekt.</p></div><div class="sect3" title="4.1.3.4. $::lxdebug"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7610"></a>4.1.3.4. $::lxdebug</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "LXDebug"</p></li><li class="listitem"><p>Wird global gecached</p></li><li class="listitem"><p>Muss immer verfügbar sein, in nahezu allen
               Funktionen</p></li></ul></div><p>
                   <code class="varname">$::lxdebug</code> stellt Debuggingfunktionen
           bereit, wie "<code class="function">enter_sub</code>" und
           "<code class="function">message</code>" und "<code class="function">dump</code>" mit
           denen man flott Informationen ins Log (tmp/kivitendo-debug.log)
           packen kann.</p><p>Beispielsweise so:</p><pre class="programlisting">$main::lxdebug-&gt;message(0, 'Meine Konfig:' . Dumper (%::myconfig));
-$main::lxdebug-&gt;message(0, 'Wer bin ich? Kunde oder Lieferant:' . $form-&gt;{vc});</pre></div><div class="sect3" title="4.1.3.5. $::auth"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7373"></a>4.1.3.5. $::auth</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "SL::Auth"</p></li><li class="listitem"><p>Wird global gecached</p></li><li class="listitem"><p>Hat eine permanente DB Verbindung zur Authdatenbank</p></li><li class="listitem"><p>Wird nach jedem Request resettet.</p></li></ul></div><p>
+$main::lxdebug-&gt;message(0, 'Wer bin ich? Kunde oder Lieferant:' . $form-&gt;{vc});</pre></div><div class="sect3" title="4.1.3.5. $::auth"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7647"></a>4.1.3.5. $::auth</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "SL::Auth"</p></li><li class="listitem"><p>Wird global gecached</p></li><li class="listitem"><p>Hat eine permanente DB Verbindung zur Authdatenbank</p></li><li class="listitem"><p>Wird nach jedem Request resettet.</p></li></ul></div><p>
                   <code class="varname">$::auth</code> stellt Funktionen bereit um die
           Rechte des aktuellen Users abzufragen. Obwohl diese Informationen
           vom aktuellen User abhängen wird das Objekt aus
@@ -144,7 +144,7 @@ $main::lxdebug-&gt;message(0, 'Wer bin ich? Kunde oder Lieferant:' . $form-&gt;{
           Dessen Einstellungen können über
           <code class="literal">$::auth-&gt;client</code> abgefragt werden; Rückgabewert
           ist ein Hash mit den Werten aus der Tabelle
-          <code class="literal">auth.clients</code>.</p></div><div class="sect3" title="4.1.3.6. $::lx_office_conf"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7402"></a>4.1.3.6. $::lx_office_conf</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
+          <code class="literal">auth.clients</code>.</p></div><div class="sect3" title="4.1.3.6. $::lx_office_conf"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7676"></a>4.1.3.6. $::lx_office_conf</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
               "<code class="classname">SL::LxOfficeConf</code>"</p></li><li class="listitem"><p>Global gecached</p></li><li class="listitem"><p>Repräsentation der
               <code class="filename">config/kivitendo.conf[.default]</code>-Dateien</p></li></ul></div><p>Globale Konfiguration. Configdateien werden zum Start gelesen
           und danach nicht mehr angefasst. Es ist derzeit nicht geplant, dass
@@ -154,16 +154,16 @@ $main::lxdebug-&gt;message(0, 'Wer bin ich? Kunde oder Lieferant:' . $form-&gt;{
 file_name = /tmp/kivitendo-debug.log</pre><p>ist der Key <code class="varname">file</code> im Programm als
           <code class="varname">$::lx_office_conf-&gt;{debug}{file}</code>
           erreichbar.</p><div class="warning" title="Warnung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warnung]" src="system/docbook-xsl/images/warning.png"></td><th align="left">Warnung</th></tr><tr><td align="left" valign="top"><p>Zugriff auf die Konfiguration erfolgt im Moment über
-            Hashkeys, sind also nicht gegen Tippfehler abgesichert.</p></td></tr></table></div></div><div class="sect3" title="4.1.3.7. $::instance_conf"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7438"></a>4.1.3.7. $::instance_conf</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
+            Hashkeys, sind also nicht gegen Tippfehler abgesichert.</p></td></tr></table></div></div><div class="sect3" title="4.1.3.7. $::instance_conf"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7712"></a>4.1.3.7. $::instance_conf</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
               "<code class="classname">SL::InstanceConfiguration</code>"</p></li><li class="listitem"><p>wird pro Request neu erstellt</p></li></ul></div><p>Funktioniert wie <code class="varname">$::lx_office_conf</code>,
           speichert aber Daten die von der Instanz abhängig sind. Eine Instanz
           ist hier eine Mandantendatenbank. Beispielsweise überprüft
           </p><pre class="programlisting">$::instance_conf-&gt;get_inventory_system eq 'perpetual'</pre><p>
-          ob die berüchtigte Bestandsmethode zur Anwendung kommt.</p></div><div class="sect3" title="4.1.3.8. $::dispatcher"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7459"></a>4.1.3.8. $::dispatcher</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
+          ob die berüchtigte Bestandsmethode zur Anwendung kommt.</p></div><div class="sect3" title="4.1.3.8. $::dispatcher"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7733"></a>4.1.3.8. $::dispatcher</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
               "<code class="varname">SL::Dispatcher</code>"</p></li><li class="listitem"><p>wird pro Serverprozess erstellt.</p></li><li class="listitem"><p>enthält Informationen über die technische Verbindung zum
               Server</p></li></ul></div><p>Der dritte Punkt ist auch der einzige Grund warum das Objekt
           global gespeichert wird. Wird vermutlich irgendwann in einem anderen
-          Objekt untergebracht.</p></div><div class="sect3" title="4.1.3.9. $::request"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7477"></a>4.1.3.9. $::request</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Hashref (evtl später Objekt)</p></li><li class="listitem"><p>Wird pro Request neu initialisiert.</p></li><li class="listitem"><p>Keine Unterstruktur garantiert.</p></li></ul></div><p>
+          Objekt untergebracht.</p></div><div class="sect3" title="4.1.3.9. $::request"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7751"></a>4.1.3.9. $::request</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Hashref (evtl später Objekt)</p></li><li class="listitem"><p>Wird pro Request neu initialisiert.</p></li><li class="listitem"><p>Keine Unterstruktur garantiert.</p></li></ul></div><p>
                   <code class="varname">$::request</code> ist ein generischer Platz um
           Daten "für den aktuellen Request" abzulegen. Sollte nicht für action
           at a distance benutzt werden, sondern um lokales memoizing zu
@@ -176,20 +176,20 @@ file_name = /tmp/kivitendo-debug.log</pre><p>ist der Key <code class="varname">f
               <code class="varname">$::request</code>
                      </p></li><li class="listitem"><p>Muss ich von anderen Teilen des Programms lesend drauf
               zugreifen? Dann <code class="varname">$::request</code>, aber Zugriff über
-              Wrappermethode</p></li></ul></div></div></div><div class="sect2" title="4.1.4. Ehemalige globale Variablen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7519"></a>4.1.4. Ehemalige globale Variablen</h3></div></div></div><p>Die folgenden Variablen waren einmal im Programm, und wurden
-        entfernt.</p><div class="sect3" title="4.1.4.1. $::cgi"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7524"></a>4.1.4.1. $::cgi</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>war nötig, weil cookie Methoden nicht als
+              Wrappermethode</p></li></ul></div></div></div><div class="sect2" title="4.1.4. Ehemalige globale Variablen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7793"></a>4.1.4. Ehemalige globale Variablen</h3></div></div></div><p>Die folgenden Variablen waren einmal im Programm, und wurden
+        entfernt.</p><div class="sect3" title="4.1.4.1. $::cgi"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7798"></a>4.1.4.1. $::cgi</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>war nötig, weil cookie Methoden nicht als
               Klassenfunktionen funktionieren</p></li><li class="listitem"><p>Aufruf als Klasse erzeugt Dummyobjekt was im
               Klassennamespace gehalten wird und über Requestgrenzen
               leaked</p></li><li class="listitem"><p>liegt jetzt unter
               <code class="varname">$::request-&gt;{cgi}</code>
-                     </p></li></ul></div></div><div class="sect3" title="4.1.4.2. $::all_units"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7540"></a>4.1.4.2. $::all_units</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>war nötig, weil einige Funktionen in Schleifen zum Teil
+                     </p></li></ul></div></div><div class="sect3" title="4.1.4.2. $::all_units"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7814"></a>4.1.4.2. $::all_units</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>war nötig, weil einige Funktionen in Schleifen zum Teil
               ein paar hundert mal pro Request eine Liste der Einheiten
               brauchen, und de als Parameter durch einen Riesenstack von
               Funktionen geschleift werden müssten.</p></li><li class="listitem"><p>Liegt jetzt unter
               <code class="varname">$::request-&gt;{cache}{all_units}</code>
                      </p></li><li class="listitem"><p>Wird nur in
               <code class="function">AM-&gt;retrieve_all_units()</code> gesetzt oder
-              gelesen.</p></li></ul></div></div><div class="sect3" title="4.1.4.3. %::called_subs"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7559"></a>4.1.4.3. %::called_subs</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>wurde benutzt um callsub deep recursions
+              gelesen.</p></li></ul></div></div><div class="sect3" title="4.1.4.3. %::called_subs"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7833"></a>4.1.4.3. %::called_subs</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>wurde benutzt um callsub deep recursions
               abzufangen.</p></li><li class="listitem"><p>Wurde entfernt, weil callsub nur einen Bruchteil der
               möglichen Rekursioenen darstellt, und da nie welche
               auftreten.</p></li><li class="listitem"><p>komplette recursion protection wurde entfernt.</p></li></ul></div></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03s10.html">Zurück</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch04s02.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">3.10. ZUGFeRD Rechnungen&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Zum Anfang</a></td><td width="40%" align="right" valign="top">&nbsp;4.2. Entwicklung unter FastCGI</td></tr></table></div></body></html>
\ No newline at end of file
index 02bb6c7..3c91746 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>4.2. Entwicklung unter FastCGI</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="next" href="ch04s03.html" title="4.3. Programmatische API-Aufrufe"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.2. Entwicklung unter FastCGI</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s03.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.2. Entwicklung unter FastCGI"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.fcgi"></a>4.2. Entwicklung unter FastCGI</h2></div></div></div><div class="sect2" title="4.2.1. Allgemeines"><div class="titlepage"><div><div><h3 class="title"><a name="devel.fcgi.general"></a>4.2.1. Allgemeines</h3></div></div></div><p>Wenn Änderungen in der Konfiguration von kivitendo gemacht
+   <title>4.2. Entwicklung unter FastCGI</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="next" href="ch04s03.html" title="4.3. Programmatische API-Aufrufe"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.2. Entwicklung unter FastCGI</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s03.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.2. Entwicklung unter FastCGI"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.fcgi"></a>4.2. Entwicklung unter FastCGI</h2></div></div></div><div class="sect2" title="4.2.1. Allgemeines"><div class="titlepage"><div><div><h3 class="title"><a name="devel.fcgi.general"></a>4.2.1. Allgemeines</h3></div></div></div><p>Wenn Änderungen in der Konfiguration von kivitendo gemacht
         werden, muss der Webserver neu gestartet werden.</p><p>Bei der Entwicklung für FastCGI ist auf ein paar Fallstricke zu
         achten. Dadurch, dass das Programm in einer Endlosschleife läuft,
         müssen folgende Aspekte beachtet werden.</p></div><div class="sect2" title="4.2.2. Programmende und Ausnahmen"><div class="titlepage"><div><div><h3 class="title"><a name="devel.fcgi.exiting"></a>4.2.2. Programmende und Ausnahmen</h3></div></div></div><p>Betrifft die Funktionen <code class="function">warn</code>,
index aa06420..b05a454 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>4.3. Programmatische API-Aufrufe</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s02.html" title="4.2. Entwicklung unter FastCGI"><link rel="next" href="ch04s04.html" title="4.4. SQL-Upgradedateien"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.3. Programmatische API-Aufrufe</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s02.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.3. Programmatische API-Aufrufe"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="dev-programmatic-api-calls"></a>4.3. Programmatische API-Aufrufe</h2></div></div></div><div class="sect2" title="4.3.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="dev-programmatic-api-calls.introduction"></a>4.3.1. Einführung</h3></div></div></div><p>
+   <title>4.3. Programmatische API-Aufrufe</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s02.html" title="4.2. Entwicklung unter FastCGI"><link rel="next" href="ch04s04.html" title="4.4. SQL-Upgradedateien"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.3. Programmatische API-Aufrufe</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s02.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.3. Programmatische API-Aufrufe"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="dev-programmatic-api-calls"></a>4.3. Programmatische API-Aufrufe</h2></div></div></div><div class="sect2" title="4.3.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="dev-programmatic-api-calls.introduction"></a>4.3.1. Einführung</h3></div></div></div><p>
          Es ist möglich, Funktionen in kivitendo programmatisch aus anderen Programmen aufzurufen. Dazu ist nötig, dass
          Authentifizierungsinformationen in jedem Aufruf mitgegeben werden. Dafür gibt es zwei Methoden: die HTTP-»Basic«-Authentifizierung
          oder die Übergabe als spziell benannte GET-Parameter. Neben den Authentifizierungsinformationen muss auch der zu verwendende Mandant
index aa580db..f53c439 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>4.4. SQL-Upgradedateien</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s03.html" title="4.3. Programmatische API-Aufrufe"><link rel="next" href="ch04s05.html" title="4.5. Translations and languages"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.4. SQL-Upgradedateien</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s03.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s05.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.4. SQL-Upgradedateien"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="db-upgrade-files"></a>4.4. SQL-Upgradedateien</h2></div></div></div><div class="sect2" title="4.4.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="db-upgrade-files.introduction"></a>4.4.1. Einführung</h3></div></div></div><p>Datenbankupgrades werden über einzelne Upgrade-Scripte
+   <title>4.4. SQL-Upgradedateien</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s03.html" title="4.3. Programmatische API-Aufrufe"><link rel="next" href="ch04s05.html" title="4.5. Translations and languages"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.4. SQL-Upgradedateien</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s03.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s05.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.4. SQL-Upgradedateien"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="db-upgrade-files"></a>4.4. SQL-Upgradedateien</h2></div></div></div><div class="sect2" title="4.4.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="db-upgrade-files.introduction"></a>4.4.1. Einführung</h3></div></div></div><p>Datenbankupgrades werden über einzelne Upgrade-Scripte
         gesteuert, die sich im Verzeichnis
         <code class="filename">sql/Pg-upgrade2</code> befinden. In diesem Verzeichnis
         muss pro Datenbankupgrade eine Datei existieren, die neben den
index 2ea2faa..cc2d124 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>4.5. Translations and languages</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s04.html" title="4.4. SQL-Upgradedateien"><link rel="next" href="ch04s06.html" title="4.6. Die kivitendo-Test-Suite"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.5. Translations and languages</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s04.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s06.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.5. Translations and languages"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="translations-languages"></a>4.5. Translations and languages</h2></div></div></div><div class="sect2" title="4.5.1. Introduction"><div class="titlepage"><div><div><h3 class="title"><a name="translations-languages.introduction"></a>4.5.1. Introduction</h3></div></div></div><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left">Anmerkung</th></tr><tr><td align="left" valign="top"><p>Dieser Abschnitt ist in Englisch geschrieben, um
+   <title>4.5. Translations and languages</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s04.html" title="4.4. SQL-Upgradedateien"><link rel="next" href="ch04s06.html" title="4.6. Die kivitendo-Test-Suite"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.5. Translations and languages</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s04.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s06.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.5. Translations and languages"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="translations-languages"></a>4.5. Translations and languages</h2></div></div></div><div class="sect2" title="4.5.1. Introduction"><div class="titlepage"><div><div><h3 class="title"><a name="translations-languages.introduction"></a>4.5.1. Introduction</h3></div></div></div><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left">Anmerkung</th></tr><tr><td align="left" valign="top"><p>Dieser Abschnitt ist in Englisch geschrieben, um
           internationalen Übersetzern die Arbeit zu erleichtern.</p></td></tr></table></div><p>This section describes how localization packages in kivitendo
         are built. Currently the only language fully supported is German, and
         since most of the internal messages are held in English the English
index 5a47d6e..6eddda5 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>4.6. Die kivitendo-Test-Suite</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s05.html" title="4.5. Translations and languages"><link rel="next" href="ch04s07.html" title="4.7. Stil-Richtlinien"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.6. Die kivitendo-Test-Suite</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s05.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s07.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.6. Die kivitendo-Test-Suite"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.testsuite"></a>4.6. Die kivitendo-Test-Suite</h2></div></div></div><div class="sect2" title="4.6.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="devel.testsuite.intro"></a>4.6.1. Einführung</h3></div></div></div><p>kivitendo enthält eine Suite für automatisierte Tests. Sie
+   <title>4.6. Die kivitendo-Test-Suite</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s05.html" title="4.5. Translations and languages"><link rel="next" href="ch04s07.html" title="4.7. Stil-Richtlinien"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.6. Die kivitendo-Test-Suite</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s05.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s07.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.6. Die kivitendo-Test-Suite"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.testsuite"></a>4.6. Die kivitendo-Test-Suite</h2></div></div></div><div class="sect2" title="4.6.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="devel.testsuite.intro"></a>4.6.1. Einführung</h3></div></div></div><p>kivitendo enthält eine Suite für automatisierte Tests. Sie
         basiert auf dem Standard-Perl-Modul
         <code class="literal">Test::More</code>.</p><p>Die grundlegenden Fakten sind:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Alle Tests liegen im Unterverzeichnis
             <code class="filename">t/</code>.</p></li><li class="listitem"><p>Ein Script (bzw. ein Test) in <code class="filename">t/</code>
index 442155a..c1e0dd8 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>4.7. Stil-Richtlinien</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s06.html" title="4.6. Die kivitendo-Test-Suite"><link rel="next" href="ch04s08.html" title="4.8. Dokumentation erstellen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.7. Stil-Richtlinien</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s06.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s08.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.7. Stil-Richtlinien"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.style-guide"></a>4.7. Stil-Richtlinien</h2></div></div></div><p>Die folgenden Regeln haben das Ziel, den Code möglichst gut les-
+   <title>4.7. Stil-Richtlinien</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s06.html" title="4.6. Die kivitendo-Test-Suite"><link rel="next" href="ch04s08.html" title="4.8. Dokumentation erstellen"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.7. Stil-Richtlinien</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s06.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s08.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="4.7. Stil-Richtlinien"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.style-guide"></a>4.7. Stil-Richtlinien</h2></div></div></div><p>Die folgenden Regeln haben das Ziel, den Code möglichst gut les-
       und wartbar zu machen. Dazu gehört zum Einen, dass der Code einheitlich
       eingerückt ist, aber auch, dass Mehrdeutigkeit so weit es geht vermieden
       wird (Stichworte "Klammern" oder "Hash-Keys").</p><p>Diese Regeln sind keine Schikane sondern erleichtern allen das
index 433046d..11e2252 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>4.8. Dokumentation erstellen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s07.html" title="4.7. Stil-Richtlinien"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.8. Dokumentation erstellen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s07.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;</td></tr></table><hr></div><div class="sect1" title="4.8. Dokumentation erstellen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.build-doc"></a>4.8. Dokumentation erstellen</h2></div></div></div><div class="sect2" title="4.8.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="devel.build-doc.introduction"></a>4.8.1. Einführung</h3></div></div></div><p>Diese Dokumentation ist in <span class="productname">DocBook</span>™
+   <title>4.8. Dokumentation erstellen</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"><link rel="prev" href="ch04s07.html" title="4.7. Stil-Richtlinien"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.8. Dokumentation erstellen</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s07.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 4. Entwicklerdokumentation</th><td width="20%" align="right">&nbsp;</td></tr></table><hr></div><div class="sect1" title="4.8. Dokumentation erstellen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.build-doc"></a>4.8. Dokumentation erstellen</h2></div></div></div><div class="sect2" title="4.8.1. Einführung"><div class="titlepage"><div><div><h3 class="title"><a name="devel.build-doc.introduction"></a>4.8.1. Einführung</h3></div></div></div><p>Diese Dokumentation ist in <span class="productname">DocBook</span>™
         XML geschrieben. Zum Bearbeiten reicht grundsätzlich ein Text-Editor.
         Mehr Komfort bekommt man, wenn man einen dedizierten XML-fähigen
         Editor nutzt, der spezielle Unterstützung für
index ac3f387..ce6a9ac 100644 (file)
@@ -1,9 +1,9 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>kivitendo 3.5.8: Installation, Konfiguration, Entwicklung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><link rel="next" href="ch01.html" title="Kapitel 1. Aktuelle Hinweise"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">kivitendo 3.5.8: Installation, Konfiguration,
-  Entwicklung</th></tr><tr><td width="20%" align="left">&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01.html">Weiter</a></td></tr></table><hr></div><div lang="de" class="book" title="kivitendo 3.5.8: Installation, Konfiguration, Entwicklung"><div class="titlepage"><div><div><h1 class="title"><a name="kivitendo-documentation"></a>kivitendo 3.5.8: Installation, Konfiguration,
-  Entwicklung</h1></div></div><hr></div><div class="toc"><p><b>Inhaltsverzeichnis</b></p><dl><dt><span class="chapter"><a href="ch01.html">1. Aktuelle Hinweise</a></span></dt><dt><span class="chapter"><a href="ch02.html">2. Installation und Grundkonfiguration</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch02.html#Installation-%C3%9Cbersicht">2.1. Übersicht</a></span></dt><dt><span class="sect1"><a href="ch02s02.html">2.2. Benötigte Software und Pakete</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s02.html#Betriebssystem">2.2.1. Betriebssystem</a></span></dt><dt><span class="sect2"><a href="ch02s02.html#Pakete">2.2.2. Benötigte Perl-Pakete installieren</a></span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e675">2.2.3. Andere Pakete installieren</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s03.html">2.3. Manuelle Installation des Programmpaketes</a></span></dt><dt><span class="sect1"><a href="ch02s04.html">2.4. kivitendo-Konfigurationsdatei</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s04.html#config.config-file.introduction">2.4.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.sections-parameters">2.4.2. Abschnitte und Parameter</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.prior-versions">2.4.3. Versionen vor 2.6.3</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s05.html">2.5. Anpassung der PostgreSQL-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s05.html#Zeichens%C3%A4tze-die-Verwendung-von-UTF-8">2.5.1. Zeichensätze/die Verwendung von Unicode/UTF-8</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#%C3%84nderungen-an-Konfigurationsdateien">2.5.2. Änderungen an Konfigurationsdateien</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Erweiterung-f%C3%BCr-servergespeicherte-Prozeduren">2.5.3. Erweiterung für servergespeicherte Prozeduren</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Erweiterung-f%C3%BCr-trigram">2.5.4. Erweiterung für Trigram Prozeduren</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Datenbankbenutzer-anlegen">2.5.5. Datenbankbenutzer anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s06.html">2.6. Webserver-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s06.html#d0e1149">2.6.1. Grundkonfiguration mittels CGI</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#Apache-Konfiguration.FCGI">2.6.2. Konfiguration für FastCGI/FCGI</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1303">2.6.3. Authentifizierung mittels HTTP Basic Authentication</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1319">2.6.4. Aktivierung von mod_rewrite/directory_match für git basierte Installationen</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1333">2.6.5. Weitergehende Konfiguration</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s07.html">2.7. Der Task-Server</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s07.html#Konfiguration-des-Task-Servers">2.7.1. Verfügbare und notwendige Konfigurationsoptionen</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Konfiguration-der-Mandanten-fuer-den-Task-Servers">2.7.2. Konfiguration der Mandanten für den Task-Server</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Einbinden-in-den-Boot-Prozess">2.7.3. Automatisches Starten des Task-Servers beim Booten</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Prozesskontrolle">2.7.4. Wie der Task-Server gestartet und beendet wird</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Tasks konfigurieren">2.7.5. Exemplarische Konfiguration eines Hintergrund-Jobs, der die Jahreszahl in allen Nummernkreisen zum Jahreswechsel erhöht</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s08.html">2.8. Benutzerauthentifizierung und Administratorpasswort</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s08.html#Grundlagen-zur-Benutzerauthentifizierung">2.8.1. Grundlagen zur Benutzerauthentifizierung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Administratorpasswort">2.8.2. Administratorpasswort</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Authentifizierungsdatenbank">2.8.3. Authentifizierungsdatenbank</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Passwort%C3%BCberpr%C3%BCfung">2.8.4. Passwortüberprüfung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Name-des-Session-Cookies">2.8.5. Name des Session-Cookies</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Anlegen-der-Authentifizierungsdatenbank">2.8.6. Anlegen der Authentifizierungsdatenbank</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s09.html">2.9. Mandanten-, Benutzer- und Gruppenverwaltung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s09.html#Zusammenh%C3%A4nge">2.9.1. Zusammenhänge</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Mandanten-Benutzer-Gruppen">2.9.2. Mandanten, Benutzer und Gruppen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Datenbanken-anlegen">2.9.3. Datenbanken anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Gruppen-anlegen">2.9.4. Gruppen anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Benutzer-anlegen">2.9.5. Benutzer anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Mandanten-anlegen">2.9.6. Mandanten anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s10.html">2.10. Drucker- und Systemverwaltung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s10.html#Druckeradministration">2.10.1. Druckeradministration</a></span></dt><dt><span class="sect2"><a href="ch02s10.html#System">2.10.2. System sperren / entsperren</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s11.html">2.11. E-Mail-Versand aus kivitendo heraus</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s11.html#config.sending-email.sendmail">2.11.1. Versand über lokalen E-Mail-Server</a></span></dt><dt><span class="sect2"><a href="ch02s11.html#config.sending-email.smtp">2.11.2. Versand über einen SMTP-Server</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s12.html">2.12. Drucken mit kivitendo</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s12.html#Vorlagenverzeichnis-anlegen">2.12.1. Vorlagenverzeichnis anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#Vorlagen-RB">2.12.2. Der Druckvorlagensatz RB</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#Vorlagen-rev-odt">2.12.3. Der Druckvorlagensatz rev-odt</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#allgemeine-hinweise-zu-latex">2.12.4. Allgemeine Hinweise zu LaTeX Vorlagen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s13.html">2.13. OpenDocument-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s13.html#d0e2440">2.13.1. OpenDocument (odt) Druckvorlagen mit Makros</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s14.html">2.14. Nomenklatur</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s14.html#booking.dates">2.14.1. Datum bei Buchungen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s15.html">2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung:
+   <title>kivitendo 3.6.1: Installation, Konfiguration, Entwicklung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><link rel="next" href="ch01.html" title="Kapitel 1. Aktuelle Hinweise"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">kivitendo 3.6.1: Installation, Konfiguration,
+  Entwicklung</th></tr><tr><td width="20%" align="left">&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01.html">Weiter</a></td></tr></table><hr></div><div lang="de" class="book" title="kivitendo 3.6.1: Installation, Konfiguration, Entwicklung"><div class="titlepage"><div><div><h1 class="title"><a name="kivitendo-documentation"></a>kivitendo 3.6.1: Installation, Konfiguration,
+  Entwicklung</h1></div></div><hr></div><div class="toc"><p><b>Inhaltsverzeichnis</b></p><dl><dt><span class="chapter"><a href="ch01.html">1. Aktuelle Hinweise</a></span></dt><dt><span class="chapter"><a href="ch02.html">2. Installation und Grundkonfiguration</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch02.html#Installation-%C3%9Cbersicht">2.1. Übersicht</a></span></dt><dt><span class="sect1"><a href="ch02s02.html">2.2. Benötigte Software und Pakete</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s02.html#Betriebssystem">2.2.1. Betriebssystem</a></span></dt><dt><span class="sect2"><a href="ch02s02.html#Pakete">2.2.2. Benötigte Perl-Pakete installieren</a></span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e718">2.2.3. Andere Pakete installieren</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s03.html">2.3. Manuelle Installation des Programmpaketes</a></span></dt><dt><span class="sect1"><a href="ch02s04.html">2.4. kivitendo-Konfigurationsdatei</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s04.html#config.config-file.introduction">2.4.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.sections-parameters">2.4.2. Abschnitte und Parameter</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.prior-versions">2.4.3. Versionen vor 2.6.3</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s05.html">2.5. Anpassung der PostgreSQL-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s05.html#Zeichens%C3%A4tze-die-Verwendung-von-UTF-8">2.5.1. Zeichensätze/die Verwendung von Unicode/UTF-8</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#%C3%84nderungen-an-Konfigurationsdateien">2.5.2. Änderungen an Konfigurationsdateien</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Erweiterung-f%C3%BCr-servergespeicherte-Prozeduren">2.5.3. Erweiterung für servergespeicherte Prozeduren</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Erweiterung-f%C3%BCr-trigram">2.5.4. Erweiterung für Trigram Prozeduren</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Datenbankbenutzer-anlegen">2.5.5. Datenbankbenutzer anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s06.html">2.6. Webserver-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s06.html#d0e1192">2.6.1. Grundkonfiguration mittels CGI</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#Apache-Konfiguration.FCGI">2.6.2. Konfiguration für FastCGI/FCGI</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1346">2.6.3. Authentifizierung mittels HTTP Basic Authentication</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1362">2.6.4. Aktivierung von mod_rewrite/directory_match für git basierte Installationen</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1376">2.6.5. Weitergehende Konfiguration</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1387">2.6.6. Aktivierung von Apache2 modsecurity</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s07.html">2.7. Der Task-Server</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s07.html#Konfiguration-des-Task-Servers">2.7.1. Verfügbare und notwendige Konfigurationsoptionen</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Konfiguration-der-Mandanten-fuer-den-Task-Servers">2.7.2. Konfiguration der Mandanten für den Task-Server</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Einbinden-in-den-Boot-Prozess">2.7.3. Automatisches Starten des Task-Servers beim Booten</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Prozesskontrolle">2.7.4. Wie der Task-Server gestartet und beendet wird</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Tasks-konfigurieren">2.7.5. Exemplarische Konfiguration eines Hintergrund-Jobs, der die Jahreszahl in allen Nummernkreisen zum Jahreswechsel erhöht</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s08.html">2.8. Benutzerauthentifizierung und Administratorpasswort</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s08.html#Grundlagen-zur-Benutzerauthentifizierung">2.8.1. Grundlagen zur Benutzerauthentifizierung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Administratorpasswort">2.8.2. Administratorpasswort</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Authentifizierungsdatenbank">2.8.3. Authentifizierungsdatenbank</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Passwort%C3%BCberpr%C3%BCfung">2.8.4. Passwortüberprüfung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Name-des-Session-Cookies">2.8.5. Name des Session-Cookies</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Anlegen-der-Authentifizierungsdatenbank">2.8.6. Anlegen der Authentifizierungsdatenbank</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s09.html">2.9. Mandanten-, Benutzer- und Gruppenverwaltung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s09.html#Zusammenh%C3%A4nge">2.9.1. Zusammenhänge</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Mandanten-Benutzer-Gruppen">2.9.2. Mandanten, Benutzer und Gruppen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Datenbanken-anlegen">2.9.3. Datenbanken anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Gruppen-anlegen">2.9.4. Gruppen anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Benutzer-anlegen">2.9.5. Benutzer anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Mandanten-anlegen">2.9.6. Mandanten anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s10.html">2.10. Drucker- und Systemverwaltung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s10.html#Druckeradministration">2.10.1. Druckeradministration</a></span></dt><dt><span class="sect2"><a href="ch02s10.html#System">2.10.2. System sperren / entsperren</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s11.html">2.11. E-Mail-Versand aus kivitendo heraus</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s11.html#config.sending-email.sendmail">2.11.1. Versand über lokalen E-Mail-Server</a></span></dt><dt><span class="sect2"><a href="ch02s11.html#config.sending-email.smtp">2.11.2. Versand über einen SMTP-Server</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s12.html">2.12. Drucken mit kivitendo</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s12.html#Vorlagenverzeichnis-anlegen">2.12.1. Vorlagenverzeichnis anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#Vorlagen-RB">2.12.2. Der Druckvorlagensatz RB</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#Vorlagen-rev-odt">2.12.3. Der Druckvorlagensatz rev-odt</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#allgemeine-hinweise-zu-latex">2.12.4. Allgemeine Hinweise zu LaTeX Vorlagen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s13.html">2.13. OpenDocument-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s13.html#d0e2489">2.13.1. OpenDocument (odt) Druckvorlagen mit Makros</a></span></dt><dt><span class="sect2"><a href="ch02s13.html#d0e2644">2.13.2. Schweizer QR-Rechnung mit OpenDocument Vorlagen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s14.html">2.14. Nomenklatur</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s14.html#booking.dates">2.14.1. Datum bei Buchungen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s15.html">2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung:
       EUR</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s15.html#config.eur.introduction">2.15.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s15.html#config.eur.parameters">2.15.2. Konfigurationsparameter</a></span></dt><dt><span class="sect2"><a href="ch02s15.html#config.eur.setting-parameters">2.15.3. Festlegen der Parameter</a></span></dt><dt><span class="sect2"><a href="ch02s15.html#config.eur.inventory-system-perpetual">2.15.4. Bemerkungen zur Bestandsmethode</a></span></dt><dt><span class="sect2"><a href="ch02s15.html#config.eur.knonw-issues">2.15.5. Bekannte Probleme</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s16.html">2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s16.html#config.skr04-update-3804.introduction">2.16.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s16.html#config.skr04-update-3804.create-chart">2.16.2. Konto 3804 manuell anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s17.html">2.17. Verhalten des Bilanzberichts</a></span></dt><dt><span class="sect1"><a href="ch02s18.html">2.18. Erfolgsrechnung</a></span></dt><dt><span class="sect1"><a href="ch02s19.html">2.19. Rundung in Verkaufsbelegen</a></span></dt><dt><span class="sect1"><a href="ch02s20.html">2.20. Einstellungen pro Mandant</a></span></dt><dt><span class="sect1"><a href="ch02s21.html">2.21. kivitendo ERP verwenden</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch03.html">3. Features und Funktionen</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch03.html#features.periodic-invoices">3.1. Wiederkehrende Rechnungen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.introduction">3.1.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.configuration">3.1.2. Konfiguration</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.variables">3.1.3. Spezielle Variablen</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.reports">3.1.4. Auflisten</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.task-server">3.1.5. Erzeugung der eigentlichen Rechnungen</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.create-for-current-month">3.1.6. Erste Rechnung für aktuellen Monat erstellen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s02.html">3.2. Bankerweiterung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s02.html#features.bank.introduction">3.2.1. Einführung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s03.html">3.3. Dokumentenvorlagen und verfügbare Variablen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.einf%C3%BChrung">3.3.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.variablen-ausgeben">3.3.2. Variablen ausgeben</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.verwendung-in-druckbefehlen">3.3.3. Verwendung in Druckbefehlen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.tag-style">3.3.4. Anfang und Ende der Tags verändern</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.zuordnung-dateinamen">3.3.5. Zuordnung von den Dateinamen zu den Funktionen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.dateinamen-erweitert">3.3.6. Sprache, Drucker und E-Mail</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.allgemeine-variablen">3.3.7. Allgemeine Variablen, die in allen Vorlagen vorhanden
         sind</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.invoice">3.3.8. Variablen in Rechnungen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.dunning">3.3.9. Variablen in Mahnungen und Rechnungen über Mahngebühren</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.andere-vorlagen">3.3.10. Variablen in anderen Vorlagen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.bloecke">3.3.11. Blöcke, bedingte Anweisungen und Schleifen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.markup">3.3.12. Markup-Code zur Textformatierung innerhalb von
-        Formularen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.anrede">3.3.13. Hinweise zur Anrede</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s04.html">3.4. Excel-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s04.html#excel-templates.summary">3.4.1. Zusammenfassung</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.usage">3.4.2. Bedienung</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.syntax">3.4.3. Variablensyntax</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.limitations">3.4.4. Einschränkungen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s05.html">3.5. Mandantenkonfiguration Lager</a></span></dt><dt><span class="sect1"><a href="ch03s06.html">3.6. Schweizer Kontenpläne</a></span></dt><dt><span class="sect1"><a href="ch03s07.html">3.7. Artikelklassifizierung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s07.html#d0e6543">3.7.1. Übersicht</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6548">3.7.2. Basisklassifizierung</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6578">3.7.3. Attribute</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6609">3.7.4. Zwei-Zeichen Abkürzung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s08.html">3.8. Dateiverwaltung (Mini-DMS)</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s08.html#d0e6621">3.8.1. Übersicht</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6648">3.8.2. Struktur</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6700">3.8.3. Anwendung</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6743">3.8.4. Konfigurierung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s09.html">3.9. Webshop-Api</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s09.html#d0e6808">3.9.1. Rechte für die Webshopapi</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6823">3.9.2. Konfiguration</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6831">3.9.3. Webshopartikel</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6855">3.9.4. Bestellimport</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6908">3.9.5. Mapping der Daten</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s10.html">3.10. ZUGFeRD Rechnungen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s10.html#features.zugferd.preamble">3.10.1. Vorbedingung</a></span></dt><dt><span class="sect2"><a href="ch03s10.html#features.zugferd.summary">3.10.2. Übersicht</a></span></dt><dt><span class="sect2"><a href="ch03s10.html#features.zugferd.create_zugferd_bills">3.10.3. Erstellen von ZUGFeRD Rechnungen in Kivitendo</a></span></dt><dt><span class="sect2"><a href="ch03s10.html#features.zugferd.read_zugferd_bills">3.10.4. Einlesen von ZUGFeRD Rechnungen in Kivitendo</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch04.html">4. Entwicklerdokumentation</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch04.html#devel.globals">4.1. Globale Variablen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04.html#d0e6997">4.1.1. Wie sehen globale Variablen in Perl aus?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e7098">4.1.2. Warum sind globale Variablen ein Problem?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e7131">4.1.3. Kanonische globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e7519">4.1.4. Ehemalige globale Variablen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s02.html">4.2. Entwicklung unter FastCGI</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.general">4.2.1. Allgemeines</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.exiting">4.2.2. Programmende und Ausnahmen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.globals">4.2.3. Globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.performance">4.2.4. Performance und Statistiken</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s03.html">4.3. Programmatische API-Aufrufe</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.introduction">4.3.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.client_selection">4.3.2. Wahl des Mandanten</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.http_basic_authentication">4.3.3. HTTP-»Basic«-Authentifizierung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.authentication_via_parameters">4.3.4. Authentifizierung mit Parametern</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.examples">4.3.5. Beispiele</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s04.html">4.4. SQL-Upgradedateien</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.introduction">4.4.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.format">4.4.2. Format der Kontrollinformationen</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.format-perl-files">4.4.3. Format von in Perl geschriebenen
+        Formularen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.anrede">3.3.13. Hinweise zur Anrede</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s04.html">3.4. Excel-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s04.html#excel-templates.summary">3.4.1. Zusammenfassung</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.usage">3.4.2. Bedienung</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.syntax">3.4.3. Variablensyntax</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.limitations">3.4.4. Einschränkungen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s05.html">3.5. Mandantenkonfiguration Lager</a></span></dt><dt><span class="sect1"><a href="ch03s06.html">3.6. Schweizer Kontenpläne</a></span></dt><dt><span class="sect1"><a href="ch03s07.html">3.7. Artikelklassifizierung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s07.html#d0e6817">3.7.1. Übersicht</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6822">3.7.2. Basisklassifizierung</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6852">3.7.3. Attribute</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6883">3.7.4. Zwei-Zeichen Abkürzung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s08.html">3.8. Dateiverwaltung (Mini-DMS)</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s08.html#d0e6895">3.8.1. Übersicht</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6922">3.8.2. Struktur</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6974">3.8.3. Anwendung</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e7017">3.8.4. Konfigurierung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s09.html">3.9. Webshop-Api</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s09.html#d0e7082">3.9.1. Rechte für die Webshopapi</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e7097">3.9.2. Konfiguration</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e7105">3.9.3. Webshopartikel</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e7129">3.9.4. Bestellimport</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e7182">3.9.5. Mapping der Daten</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s10.html">3.10. ZUGFeRD Rechnungen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s10.html#features.zugferd.preamble">3.10.1. Vorbedingung</a></span></dt><dt><span class="sect2"><a href="ch03s10.html#features.zugferd.summary">3.10.2. Übersicht</a></span></dt><dt><span class="sect2"><a href="ch03s10.html#features.zugferd.create_zugferd_bills">3.10.3. Erstellen von ZUGFeRD Rechnungen in Kivitendo</a></span></dt><dt><span class="sect2"><a href="ch03s10.html#features.zugferd.read_zugferd_bills">3.10.4. Einlesen von ZUGFeRD Rechnungen in Kivitendo</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch04.html">4. Entwicklerdokumentation</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch04.html#devel.globals">4.1. Globale Variablen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04.html#d0e7271">4.1.1. Wie sehen globale Variablen in Perl aus?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e7372">4.1.2. Warum sind globale Variablen ein Problem?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e7405">4.1.3. Kanonische globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e7793">4.1.4. Ehemalige globale Variablen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s02.html">4.2. Entwicklung unter FastCGI</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.general">4.2.1. Allgemeines</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.exiting">4.2.2. Programmende und Ausnahmen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.globals">4.2.3. Globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.performance">4.2.4. Performance und Statistiken</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s03.html">4.3. Programmatische API-Aufrufe</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.introduction">4.3.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.client_selection">4.3.2. Wahl des Mandanten</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.http_basic_authentication">4.3.3. HTTP-»Basic«-Authentifizierung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.authentication_via_parameters">4.3.4. Authentifizierung mit Parametern</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.examples">4.3.5. Beispiele</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s04.html">4.4. SQL-Upgradedateien</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.introduction">4.4.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.format">4.4.2. Format der Kontrollinformationen</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.format-perl-files">4.4.3. Format von in Perl geschriebenen
         Datenbankupgradescripten</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.dbupgrade-tool">4.4.4. Hilfsscript dbupgrade2_tool.pl</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s05.html">4.5. Translations and languages</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s05.html#translations-languages.introduction">4.5.1. Introduction</a></span></dt><dt><span class="sect2"><a href="ch04s05.html#translations-languages.character-set">4.5.2. Character set</a></span></dt><dt><span class="sect2"><a href="ch04s05.html#translations-languages.file-structure">4.5.3. File structure</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s06.html">4.6. Die kivitendo-Test-Suite</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.intro">4.6.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.prerequisites">4.6.2. Voraussetzungen</a></span></dt><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.execution">4.6.3. Existierende Tests ausführen</a></span></dt><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.meaning_of_scripts">4.6.4. Bedeutung der verschiedenen Test-Scripte</a></span></dt><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.create_new">4.6.5. Neue Test-Scripte erstellen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s07.html">4.7. Stil-Richtlinien</a></span></dt><dt><span class="sect1"><a href="ch04s08.html">4.8. Dokumentation erstellen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s08.html#devel.build-doc.introduction">4.8.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s08.html#devel.build-doc.required-software">4.8.2. Benötigte Software</a></span></dt><dt><span class="sect2"><a href="ch04s08.html#devel.build-doc.build">4.8.3. PDFs und HTML-Seiten erstellen</a></span></dt><dt><span class="sect2"><a href="ch04s08.html#devel.build-doc.repository">4.8.4. Einchecken in das Git-Repository</a></span></dt></dl></dd></dl></dd></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left">&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right" valign="top">&nbsp;Kapitel 1. Aktuelle Hinweise</td></tr></table></div></body></html>
\ No newline at end of file
diff --git a/doc/html/system/docbook-xsl/images/tip.png b/doc/html/system/docbook-xsl/images/tip.png
new file mode 100644 (file)
index 0000000..5c4aab3
Binary files /dev/null and b/doc/html/system/docbook-xsl/images/tip.png differ
index da3753f..205b043 100644 (file)
Binary files a/doc/kivitendo-Dokumentation.pdf and b/doc/kivitendo-Dokumentation.pdf differ
index 6fbe711..eb5cd2a 100644 (file)
@@ -217,6 +217,7 @@ als freundliche Checkliste zum Ausdrucken und Erweitern.
 * VERSION auf aktuelle Version setzen
  - Changelog auf Tagesdatum plus Versionssnummer
  - dokumentation.xml Versionsnummer anpassen
+ - im Dokument UPGRADE Versionsnummer anpassen
  - bei der Datei VERSION Versionsnummer anpassen
 
 
diff --git a/image/Bildschirmfoto-kivitendo-steigmann-3.3.0-MozillaFirefox.png b/image/Bildschirmfoto-kivitendo-steigmann-3.3.0-MozillaFirefox.png
new file mode 100644 (file)
index 0000000..1c13c50
Binary files /dev/null and b/image/Bildschirmfoto-kivitendo-steigmann-3.3.0-MozillaFirefox.png differ
diff --git a/image/CH-Kreuz_7mm.png b/image/CH-Kreuz_7mm.png
new file mode 100644 (file)
index 0000000..41d3c5f
Binary files /dev/null and b/image/CH-Kreuz_7mm.png differ
diff --git a/image/kivitendo_corona.png b/image/kivitendo_corona.png
deleted file mode 100644 (file)
index d6f3d03..0000000
Binary files a/image/kivitendo_corona.png and /dev/null differ
diff --git a/image/kivitendo_mir.png b/image/kivitendo_mir.png
new file mode 100644 (file)
index 0000000..f22f7ff
Binary files /dev/null and b/image/kivitendo_mir.png differ
index 140602a..0e3b826 100644 (file)
  * (1) http://ckeditor.com/builder\r
  *     Visit online builder to build CKEditor from scratch.\r
  *\r
- * (2) http://ckeditor.com/builder/78e5ac87b58ee46f1359aeb63013f54d\r
+ * (2) http://ckeditor.com/builder/43e1bb7eecc49e498b91b6045b267c42\r
  *     Visit online builder to build CKEditor, starting with the same setup as before.\r
  *\r
- * (3) http://ckeditor.com/builder/download/78e5ac87b58ee46f1359aeb63013f54d\r
+ * (3) http://ckeditor.com/builder/download/43e1bb7eecc49e498b91b6045b267c42\r
  *     Straight download link to the latest version of CKEditor (Optimized) with the same setup as before.\r
  *\r
  * NOTE:\r
@@ -26,7 +26,7 @@
 \r
 var CKBUILDER_CONFIG = {\r
        skin: 'moono-lisa',\r
-       preset: 'basic',\r
+       preset: 'standard',\r
        ignore: [
                '.DS_Store',
                '.bender',
@@ -56,13 +56,13 @@ var CKBUILDER_CONFIG = {
                'enterkey' : 1,
                'entities' : 1,
                'floatingspace' : 1,
+               'horizontalrule' : 1,
                'indentlist' : 1,
                'link' : 1,
                'list' : 1,
                'removeformat' : 1,
-               'resize' : 1,
-               'toolbar' : 1,
-               'wysiwygarea' : 1
+               'sourcedialog' : 1,
+               'toolbar' : 1
        },
        languages : {
                'de' : 1,
index bd15c12..068941c 100644 (file)
@@ -616,28 +616,15 @@ a.setStartAt(b,CKEDITOR.POSITION_AFTER_END)),a.collapse(!0),a.select(),a.scrollI
 {afterInit:function(b){function f(a){return h[a]}function g(b){return"force"!=c.entities_processNumerical&&a[b]?a[b]:"\x26#"+b.charCodeAt(0)+";"}var c=b.config;if(b=(b=b.dataProcessor)&&b.htmlFilter){var e=[];!1!==c.basicEntities&&e.push("nbsp,gt,lt,amp");c.entities&&(e.length&&e.push("quot,iexcl,cent,pound,curren,yen,brvbar,sect,uml,copy,ordf,laquo,not,shy,reg,macr,deg,plusmn,sup2,sup3,acute,micro,para,middot,cedil,sup1,ordm,raquo,frac14,frac12,frac34,iquest,times,divide,fnof,bull,hellip,prime,Prime,oline,frasl,weierp,image,real,trade,alefsym,larr,uarr,rarr,darr,harr,crarr,lArr,uArr,rArr,dArr,hArr,forall,part,exist,empty,nabla,isin,notin,ni,prod,sum,minus,lowast,radic,prop,infin,ang,and,or,cap,cup,int,there4,sim,cong,asymp,ne,equiv,le,ge,sub,sup,nsub,sube,supe,oplus,otimes,perp,sdot,lceil,rceil,lfloor,rfloor,lang,rang,loz,spades,clubs,hearts,diams,circ,tilde,ensp,emsp,thinsp,zwnj,zwj,lrm,rlm,ndash,mdash,lsquo,rsquo,sbquo,ldquo,rdquo,bdquo,dagger,Dagger,permil,lsaquo,rsaquo,euro"),
 c.entities_latin&&e.push("Agrave,Aacute,Acirc,Atilde,Auml,Aring,AElig,Ccedil,Egrave,Eacute,Ecirc,Euml,Igrave,Iacute,Icirc,Iuml,ETH,Ntilde,Ograve,Oacute,Ocirc,Otilde,Ouml,Oslash,Ugrave,Uacute,Ucirc,Uuml,Yacute,THORN,szlig,agrave,aacute,acirc,atilde,auml,aring,aelig,ccedil,egrave,eacute,ecirc,euml,igrave,iacute,icirc,iuml,eth,ntilde,ograve,oacute,ocirc,otilde,ouml,oslash,ugrave,uacute,ucirc,uuml,yacute,thorn,yuml,OElig,oelig,Scaron,scaron,Yuml"),c.entities_greek&&e.push("Alpha,Beta,Gamma,Delta,Epsilon,Zeta,Eta,Theta,Iota,Kappa,Lambda,Mu,Nu,Xi,Omicron,Pi,Rho,Sigma,Tau,Upsilon,Phi,Chi,Psi,Omega,alpha,beta,gamma,delta,epsilon,zeta,eta,theta,iota,kappa,lambda,mu,nu,xi,omicron,pi,rho,sigmaf,sigma,tau,upsilon,phi,chi,psi,omega,thetasym,upsih,piv"),
 c.entities_additional&&e.push(c.entities_additional));var a=k(e.join(",")),d=a.regex?"["+a.regex+"]":"a^";delete a.regex;c.entities&&c.entities_processNumerical&&(d="[^ -~]|"+d);var d=new RegExp(d,"g"),h=k("nbsp,gt,lt,amp,shy",!0),l=new RegExp(h.regex,"g");b.addRules({text:function(a){return a.replace(l,f).replace(d,g)}},{applyToAll:!0,excludeNestedEditable:!0})}}})})();CKEDITOR.config.basicEntities=!0;CKEDITOR.config.entities=!0;CKEDITOR.config.entities_latin=!0;CKEDITOR.config.entities_greek=!0;
-CKEDITOR.config.entities_additional="#39";(function(){function k(a){var l=a.config,p=a.fire("uiSpace",{space:"top",html:""}).html,t=function(){function f(a,c,e){b.setStyle(c,w(e));b.setStyle("position",a)}function e(a){var b=k.getDocumentPosition();switch(a){case "top":f("absolute","top",b.y-q-r);break;case "pin":f("fixed","top",x);break;case "bottom":f("absolute","top",b.y+(c.height||c.bottom-c.top)+r)}m=a}var m,k,n,c,h,q,v,p=l.floatSpaceDockedOffsetX||0,r=l.floatSpaceDockedOffsetY||0,u=l.floatSpacePinnedOffsetX||0,x=l.floatSpacePinnedOffsetY||
-0;return function(d){if(k=a.editable()){var f=d&&"focus"==d.name;f&&b.show();a.fire("floatingSpaceLayout",{show:f});b.removeStyle("left");b.removeStyle("right");n=b.getClientRect();c=k.getClientRect();h=g.getViewPaneSize();q=n.height;v="pageXOffset"in g.$?g.$.pageXOffset:CKEDITOR.document.$.documentElement.scrollLeft;m?(q+r<=c.top?e("top"):q+r>h.height-c.bottom?e("pin"):e("bottom"),d=h.width/2,d=l.floatSpacePreferRight?"right":0<c.left&&c.right<h.width&&c.width>n.width?"rtl"==l.contentsLangDirection?
+CKEDITOR.config.entities_additional="#39";(function(){function k(a){var l=a.config,p=a.fire("uiSpace",{space:"top",html:""}).html,
+el=(function(e){var p=e.$.getAttribute("position"),s=p==="absolute",o="overflow";return e.getParents().filter(function(q){var c=window.getComputedStyle(q.$);if(s&&c.position==="static")return false;return(/(auto|scroll)/).test(c[o]+c[o+"-y"]+c[o+"-x"] )})})(a.element),
+t=function(){function f(a,c,e){b.setStyle(c,w(e));b.setStyle("position",a)}function e(a){var b=k.getDocumentPosition();switch(a){case "top":f("absolute","top",b.y-q-r);break;case "pin":f("fixed","top",x);break;case "bottom":f("absolute","top",b.y+(c.height||c.bottom-c.top)+r)}m=a}var m,k,n,c,h,q,v,p=l.floatSpaceDockedOffsetX||0,r=l.floatSpaceDockedOffsetY||0,u=l.floatSpacePinnedOffsetX||0,x=l.floatSpacePinnedOffsetY||
+window.innerHeight-28;return function(d){if(k=a.editable()){var f=d&&"focus"==d.name;f&&b.show();a.fire("floatingSpaceLayout",{show:f});b.removeStyle("left");b.removeStyle("right");n=b.getClientRect();c=k.getClientRect();h=g.getViewPaneSize();q=n.height;v="pageXOffset"in g.$?g.$.pageXOffset:CKEDITOR.document.$.documentElement.scrollLeft;m?(q+r<=c.top-77?e("top"):q+r>h.height-c.bottom?e("pin"):e("bottom"),d=h.width/2,d=l.floatSpacePreferRight?"right":0<c.left&&c.right<h.width&&c.width>n.width?"rtl"==l.contentsLangDirection?
 "right":"left":d-c.left>c.right-d?"left":"right",n.width>h.width?(d="left",f=0):(f="left"==d?0<c.left?c.left:0:c.right<h.width?h.width-c.right:0,f+n.width>h.width&&(d="left"==d?"right":"left",f=0)),b.setStyle(d,w(("pin"==m?u:p)+f+("pin"==m?0:"left"==d?v:-v)))):(m="pin",e("pin"),t(d))}}}();if(p){var k=new CKEDITOR.template('\x3cdiv id\x3d"cke_{name}" class\x3d"cke {id} cke_reset_all cke_chrome cke_editor_{name} cke_float cke_{langDir} '+CKEDITOR.env.cssClass+'" dir\x3d"{langDir}" title\x3d"'+(CKEDITOR.env.gecko?
 " ":"")+'" lang\x3d"{langCode}" role\x3d"application" style\x3d"{style}"'+(a.title?' aria-labelledby\x3d"cke_{name}_arialbl"':" ")+"\x3e"+(a.title?'\x3cspan id\x3d"cke_{name}_arialbl" class\x3d"cke_voice_label"\x3e{voiceLabel}\x3c/span\x3e':" ")+'\x3cdiv class\x3d"cke_inner"\x3e\x3cdiv id\x3d"{topId}" class\x3d"cke_top" role\x3d"presentation"\x3e{content}\x3c/div\x3e\x3c/div\x3e\x3c/div\x3e'),b=CKEDITOR.document.getBody().append(CKEDITOR.dom.element.createFromHtml(k.output({content:p,id:a.id,langDir:a.lang.dir,
-langCode:a.langCode,name:a.name,style:"display:none;z-index:"+(l.baseFloatZIndex-1),topId:a.ui.spaceId("top"),voiceLabel:a.title}))),u=CKEDITOR.tools.eventsBuffer(500,t),e=CKEDITOR.tools.eventsBuffer(100,t);b.unselectable();b.on("mousedown",function(a){a=a.data;a.getTarget().hasAscendant("a",1)||a.preventDefault()});a.on("focus",function(b){t(b);a.on("change",u.input);g.on("scroll",e.input);g.on("resize",e.input)});a.on("blur",function(){b.hide();a.removeListener("change",u.input);g.removeListener("scroll",
-e.input);g.removeListener("resize",e.input)});a.on("destroy",function(){g.removeListener("scroll",e.input);g.removeListener("resize",e.input);b.clearCustomData();b.remove()});a.focusManager.hasFocus&&b.show();a.focusManager.add(b,1)}}var g=CKEDITOR.document.getWindow(),w=CKEDITOR.tools.cssLength;CKEDITOR.plugins.add("floatingspace",{init:function(a){a.on("loaded",function(){k(this)},null,null,20)}})})();(function(){function m(a){function f(a){var b=!1;g.attachListener(g,"keydown",function(){var d=c.getBody().getElementsByTag(a);if(!b){for(var e=0;e<d.count();e++)d.getItem(e).setCustomData("retain",!0);b=!0}},null,null,1);g.attachListener(g,"keyup",function(){var d=c.getElementsByTag(a);b&&(1!=d.count()||d.getItem(0).getCustomData("retain")||d.getItem(0).hasAttribute("data-cke-temp")||d.getItem(0).remove(1),b=!1)})}var b=this.editor,c=a.document,d=c.body,e=c.getElementById("cke_actscrpt");e&&e.parentNode.removeChild(e);
-(e=c.getElementById("cke_shimscrpt"))&&e.parentNode.removeChild(e);(e=c.getElementById("cke_basetagscrpt"))&&e.parentNode.removeChild(e);d.contentEditable=!0;CKEDITOR.env.ie&&(d.hideFocus=!0,d.disabled=!0,d.removeAttribute("disabled"));delete this._.isLoadingData;this.$=d;c=new CKEDITOR.dom.document(c);this.setup();this.fixInitialSelection();var g=this;CKEDITOR.env.ie&&!CKEDITOR.env.edge&&c.getDocumentElement().addClass(c.$.compatMode);CKEDITOR.env.ie&&!CKEDITOR.env.edge&&b.enterMode!=CKEDITOR.ENTER_P?
-f("p"):CKEDITOR.env.edge&&b.enterMode!=CKEDITOR.ENTER_DIV&&f("div");if(CKEDITOR.env.webkit||CKEDITOR.env.ie&&10<CKEDITOR.env.version)c.getDocumentElement().on("mousedown",function(a){a.data.getTarget().is("html")&&setTimeout(function(){b.editable().focus()})});n(b);try{b.document.$.execCommand("2D-position",!1,!0)}catch(h){}(CKEDITOR.env.gecko||CKEDITOR.env.ie&&"CSS1Compat"==b.document.$.compatMode)&&this.attachListener(this,"keydown",function(a){var c=a.data.getKeystroke();if(33==c||34==c)if(CKEDITOR.env.ie)setTimeout(function(){b.getSelection().scrollIntoView()},
-0);else if(b.window.$.innerHeight>this.$.offsetHeight){var d=b.createRange();d[33==c?"moveToElementEditStart":"moveToElementEditEnd"](this);d.select();a.data.preventDefault()}});CKEDITOR.env.ie&&this.attachListener(c,"blur",function(){try{c.$.selection.empty()}catch(a){}});CKEDITOR.env.iOS&&this.attachListener(c,"touchend",function(){a.focus()});d=b.document.getElementsByTag("title").getItem(0);d.data("cke-title",d.getText());CKEDITOR.env.ie&&(b.document.$.title=this._.docTitle);CKEDITOR.tools.setTimeout(function(){"unloaded"==
-this.status&&(this.status="ready");b.fire("contentDom");this._.isPendingFocus&&(b.focus(),this._.isPendingFocus=!1);setTimeout(function(){b.fire("dataReady")},0)},0,this)}function n(a){function f(){var c;a.editable().attachListener(a,"selectionChange",function(){var d=a.getSelection().getSelectedElement();d&&(c&&(c.detachEvent("onresizestart",b),c=null),d.$.attachEvent("onresizestart",b),c=d.$)})}function b(a){a.returnValue=!1}if(CKEDITOR.env.gecko)try{var c=a.document.$;c.execCommand("enableObjectResizing",
-!1,!a.config.disableObjectResizing);c.execCommand("enableInlineTableEditing",!1,!a.config.disableNativeTableHandles)}catch(d){}else CKEDITOR.env.ie&&11>CKEDITOR.env.version&&a.config.disableObjectResizing&&f(a)}function p(){var a=[];if(8<=CKEDITOR.document.$.documentMode){a.push("html.CSS1Compat [contenteditable\x3dfalse]{min-height:0 !important}");var f=[],b;for(b in CKEDITOR.dtd.$removeEmpty)f.push("html.CSS1Compat "+b+"[contenteditable\x3dfalse]");a.push(f.join(",")+"{display:inline-block}")}else CKEDITOR.env.gecko&&
-(a.push("html{height:100% !important}"),a.push("img:-moz-broken{-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}"));a.push("html{cursor:text;*cursor:auto}");a.push("img,input,textarea{cursor:default}");return a.join("\n")}var l;CKEDITOR.plugins.add("wysiwygarea",{init:function(a){a.config.fullPage&&a.addFeature({allowedContent:"html head title; style [media,type]; body (*)[id]; meta link [*]",requiredContent:"body"});a.addMode("wysiwyg",function(f){function b(b){b&&b.removeListener();
-a.editable(new l(a,d.$.contentWindow.document.body));a.setData(a.getData(1),f)}var c="document.open();"+(CKEDITOR.env.ie?"("+CKEDITOR.tools.fixDomain+")();":"")+"document.close();",c=CKEDITOR.env.air?"javascript:void(0)":CKEDITOR.env.ie&&!CKEDITOR.env.edge?"javascript:void(function(){"+encodeURIComponent(c)+"}())":"",d=CKEDITOR.dom.element.createFromHtml('\x3ciframe src\x3d"'+c+'" frameBorder\x3d"0"\x3e\x3c/iframe\x3e');d.setStyles({width:"100%",height:"100%"});d.addClass("cke_wysiwyg_frame").addClass("cke_reset");
-c=a.ui.space("contents");c.append(d);var e=CKEDITOR.env.ie&&!CKEDITOR.env.edge||CKEDITOR.env.gecko;if(e)d.on("load",b);var g=a.title,h=a.fire("ariaEditorHelpLabel",{}).label;g&&(CKEDITOR.env.ie&&h&&(g+=", "+h),d.setAttribute("title",g));if(h){var g=CKEDITOR.tools.getNextId(),k=CKEDITOR.dom.element.createFromHtml('\x3cspan id\x3d"'+g+'" class\x3d"cke_voice_label"\x3e'+h+"\x3c/span\x3e");c.append(k,1);d.setAttribute("aria-describedby",g)}a.on("beforeModeUnload",function(a){a.removeListener();k&&k.remove()});
-d.setAttributes({tabIndex:a.tabIndex,allowTransparency:"true"});!e&&b();a.fire("ariaWidget",d)})}});CKEDITOR.editor.prototype.addContentsCss=function(a){var f=this.config,b=f.contentsCss;CKEDITOR.tools.isArray(b)||(f.contentsCss=b?[b]:[]);f.contentsCss.push(a)};l=CKEDITOR.tools.createClass({$:function(){this.base.apply(this,arguments);this._.frameLoadedHandler=CKEDITOR.tools.addFunction(function(a){CKEDITOR.tools.setTimeout(m,0,this,a)},this);this._.docTitle=this.getWindow().getFrame().getAttribute("title")},
-base:CKEDITOR.editable,proto:{setData:function(a,f){var b=this.editor;if(f)this.setHtml(a),this.fixInitialSelection(),b.fire("dataReady");else{this._.isLoadingData=!0;b._.dataStore={id:1};var c=b.config,d=c.fullPage,e=c.docType,g=CKEDITOR.tools.buildStyleHtml(p()).replace(/<style>/,'\x3cstyle data-cke-temp\x3d"1"\x3e');d||(g+=CKEDITOR.tools.buildStyleHtml(b.config.contentsCss));var h=c.baseHref?'\x3cbase href\x3d"'+c.baseHref+'" data-cke-temp\x3d"1" /\x3e':"";d&&(a=a.replace(/<!DOCTYPE[^>]*>/i,function(a){b.docType=
-e=a;return""}).replace(/<\?xml\s[^\?]*\?>/i,function(a){b.xmlDeclaration=a;return""}));a=b.dataProcessor.toHtml(a);d?(/<body[\s|>]/.test(a)||(a="\x3cbody\x3e"+a),/<html[\s|>]/.test(a)||(a="\x3chtml\x3e"+a+"\x3c/html\x3e"),/<head[\s|>]/.test(a)?/<title[\s|>]/.test(a)||(a=a.replace(/<head[^>]*>/,"$\x26\x3ctitle\x3e\x3c/title\x3e")):a=a.replace(/<html[^>]*>/,"$\x26\x3chead\x3e\x3ctitle\x3e\x3c/title\x3e\x3c/head\x3e"),h&&(a=a.replace(/<head[^>]*?>/,"$\x26"+h)),a=a.replace(/<\/head\s*>/,g+"$\x26"),a=
-e+a):a=c.docType+'\x3chtml dir\x3d"'+c.contentsLangDirection+'" lang\x3d"'+(c.contentsLanguage||b.langCode)+'"\x3e\x3chead\x3e\x3ctitle\x3e'+this._.docTitle+"\x3c/title\x3e"+h+g+"\x3c/head\x3e\x3cbody"+(c.bodyId?' id\x3d"'+c.bodyId+'"':"")+(c.bodyClass?' class\x3d"'+c.bodyClass+'"':"")+"\x3e"+a+"\x3c/body\x3e\x3c/html\x3e";CKEDITOR.env.gecko&&(a=a.replace(/<body/,'\x3cbody contenteditable\x3d"true" '),2E4>CKEDITOR.env.version&&(a=a.replace(/<body[^>]*>/,"$\x26\x3c!-- cke-content-start --\x3e")));
-c='\x3cscript id\x3d"cke_actscrpt" type\x3d"text/javascript"'+(CKEDITOR.env.ie?' defer\x3d"defer" ':"")+"\x3evar wasLoaded\x3d0;function onload(){if(!wasLoaded)window.parent.CKEDITOR.tools.callFunction("+this._.frameLoadedHandler+",window);wasLoaded\x3d1;}"+(CKEDITOR.env.ie?"onload();":'document.addEventListener("DOMContentLoaded", onload, false );')+"\x3c/script\x3e";CKEDITOR.env.ie&&9>CKEDITOR.env.version&&(c+='\x3cscript id\x3d"cke_shimscrpt"\x3ewindow.parent.CKEDITOR.tools.enableHtml5Elements(document)\x3c/script\x3e');
-h&&CKEDITOR.env.ie&&10>CKEDITOR.env.version&&(c+='\x3cscript id\x3d"cke_basetagscrpt"\x3evar baseTag \x3d document.querySelector( "base" );baseTag.href \x3d baseTag.href;\x3c/script\x3e');a=a.replace(/(?=\s*<\/(:?head)>)/,c);this.clearCustomData();this.clearListeners();b.fire("contentDomUnload");var k=this.getDocument();try{k.write(a)}catch(l){setTimeout(function(){k.write(a)},0)}}},getData:function(a){if(a)return this.getHtml();a=this.editor;var f=a.config,b=f.fullPage,c=b&&a.docType,d=b&&a.xmlDeclaration,
-e=this.getDocument(),b=b?e.getDocumentElement().getOuterHtml():e.getBody().getHtml();CKEDITOR.env.gecko&&f.enterMode!=CKEDITOR.ENTER_BR&&(b=b.replace(/<br>(?=\s*(:?$|<\/body>))/,""));b=a.dataProcessor.toDataFormat(b);d&&(b=d+"\n"+b);c&&(b=c+"\n"+b);return b},focus:function(){this._.isLoadingData?this._.isPendingFocus=!0:l.baseProto.focus.call(this)},detach:function(){var a=this.editor,f=a.document,b;try{b=a.window.getFrame()}catch(c){}l.baseProto.detach.call(this);this.clearCustomData();f.getDocumentElement().clearCustomData();
-CKEDITOR.tools.removeFunction(this._.frameLoadedHandler);b&&b.getParent()?(b.clearCustomData(),(a=b.removeCustomData("onResize"))&&a.removeListener(),b.remove()):CKEDITOR.warn("editor-destroy-iframe")}}})})();CKEDITOR.config.disableObjectResizing=!1;CKEDITOR.config.disableNativeTableHandles=!0;CKEDITOR.config.disableNativeSpellChecker=!0;(function(){function m(a,b){var e,f;b.on("refresh",function(a){var b=[k],c;for(c in a.data.states)b.push(a.data.states[c]);this.setState(CKEDITOR.tools.search(b,p)?p:k)},b,null,100);b.on("exec",function(b){e=a.getSelection();f=e.createBookmarks(1);b.data||(b.data={});b.data.done=!1},b,null,0);b.on("exec",function(){a.forceNextSelectionCheck();e.selectBookmarks(f)},b,null,100)}var k=CKEDITOR.TRISTATE_DISABLED,p=CKEDITOR.TRISTATE_OFF;CKEDITOR.plugins.add("indent",{init:function(a){var b=CKEDITOR.plugins.indent.genericDefinition;
+langCode:a.langCode,name:a.name,style:"display:none;z-index:"+(l.baseFloatZIndex-1),topId:a.ui.spaceId("top"),voiceLabel:a.title}))),u=CKEDITOR.tools.eventsBuffer(500,t),e=CKEDITOR.tools.eventsBuffer(10,t);b.unselectable();b.on("mousedown",function(a){a=a.data;a.getTarget().hasAscendant("a",1)||a.preventDefault()});a.on("focus",function(b){t(b);a.on("change",u.input);g.on("scroll",e.input);el.forEach(function(i){i.on("scroll",e.input)});g.on("resize",e.input)});a.on("blur",function(){b.hide();a.removeListener("change",u.input);g.removeListener("scroll",
+e.input);el.forEach(function(i){i.removeListener("scroll",e.input)});
+g.removeListener("resize",e.input)});a.on("destroy",function(){g.removeListener("scroll",e.input);el.forEach(function(i){i.removeListener("scroll",e.input)});g.removeListener("resize",e.input);b.clearCustomData();b.remove()});a.focusManager.hasFocus&&b.show();a.focusManager.add(b,1)}}var g=CKEDITOR.document.getWindow(),w=CKEDITOR.tools.cssLength;CKEDITOR.plugins.add("floatingspace",{init:function(a){a.on("loaded",function(){k(this)},null,null,20)}})})();(function(){var b={canUndo:!1,exec:function(a){var b=a.document.createElement("hr");a.insertElement(b)},allowedContent:"hr",requiredContent:"hr"};CKEDITOR.plugins.add("horizontalrule",{init:function(a){a.blockless||(a.addCommand("horizontalrule",b),a.ui.addButton&&a.ui.addButton("HorizontalRule",{label:a.lang.horizontalrule.toolbar,command:"horizontalrule",toolbar:"insert,40"}))}})})();(function(){function m(a,b){var e,f;b.on("refresh",function(a){var b=[k],c;for(c in a.data.states)b.push(a.data.states[c]);this.setState(CKEDITOR.tools.search(b,p)?p:k)},b,null,100);b.on("exec",function(b){e=a.getSelection();f=e.createBookmarks(1);b.data||(b.data={});b.data.done=!1},b,null,0);b.on("exec",function(){a.forceNextSelectionCheck();e.selectBookmarks(f)},b,null,100)}var k=CKEDITOR.TRISTATE_DISABLED,p=CKEDITOR.TRISTATE_OFF;CKEDITOR.plugins.add("indent",{init:function(a){var b=CKEDITOR.plugins.indent.genericDefinition;
 m(a,a.addCommand("indent",new b(!0)));m(a,a.addCommand("outdent",new b));a.ui.addButton&&(a.ui.addButton("Indent",{label:a.lang.indent.indent,command:"indent",directional:!0,toolbar:"indent,20"}),a.ui.addButton("Outdent",{label:a.lang.indent.outdent,command:"outdent",directional:!0,toolbar:"indent,10"}));a.on("dirChanged",function(b){var f=a.createRange(),l=b.data.node;f.setStartBefore(l);f.setEndAfter(l);for(var n=new CKEDITOR.dom.walker(f),c;c=n.next();)if(c.type==CKEDITOR.NODE_ELEMENT)if(!c.equals(l)&&
 c.getDirection())f.setStartAfter(c),n=new CKEDITOR.dom.walker(f);else{var d=a.config.indentClasses;if(d)for(var g="ltr"==b.data.dir?["_rtl",""]:["","_rtl"],h=0;h<d.length;h++)c.hasClass(d[h]+g[0])&&(c.removeClass(d[h]+g[0]),c.addClass(d[h]+g[1]));d=c.getStyle("margin-right");g=c.getStyle("margin-left");d?c.setStyle("margin-left",d):c.removeStyle("margin-left");g?c.setStyle("margin-right",g):c.removeStyle("margin-right")}})}});CKEDITOR.plugins.indent={genericDefinition:function(a){this.isIndent=!!a;
 this.startDisabled=!this.isIndent},specificDefinition:function(a,b,e){this.name=b;this.editor=a;this.jobs={};this.enterBr=a.config.enterMode==CKEDITOR.ENTER_BR;this.isIndent=!!e;this.relatedGlobal=e?"indent":"outdent";this.indentKey=e?9:CKEDITOR.SHIFT+9;this.database={}},registerCommands:function(a,b){a.on("pluginsLoaded",function(){for(var a in b)(function(a,b){var e=a.getCommand(b.relatedGlobal),c;for(c in b.jobs)e.on("exec",function(d){d.data.done||(a.fire("lockSnapshot"),b.execJob(a,c)&&(d.data.done=
@@ -807,8 +794,4 @@ C(b,e,f);m.cancel()}}else d.range.setEndAt(h,CKEDITOR.POSITION_BEFORE_END),(a=d.
 CKEDITOR.plugins.removeformat={commands:{removeformat:{exec:function(a){for(var h=a._.removeFormatRegex||(a._.removeFormatRegex=new RegExp("^(?:"+a.config.removeFormatTags.replace(/,/g,"|")+")$","i")),e=a._.removeAttributes||(a._.removeAttributes=a.config.removeFormatAttributes.split(",")),f=CKEDITOR.plugins.removeformat.filter,m=a.getSelection().getRanges(),n=m.createIterator(),p=function(a){return a.type==CKEDITOR.NODE_ELEMENT},c;c=n.getNextRange();){c.collapsed||c.enlarge(CKEDITOR.ENLARGE_ELEMENT);
 var l=c.createBookmark(),b=l.startNode,d=l.endNode,k=function(b){for(var c=a.elementPath(b),e=c.elements,d=1,g;(g=e[d])&&!g.equals(c.block)&&!g.equals(c.blockLimit);d++)h.test(g.getName())&&f(a,g)&&b.breakParent(g)};k(b);if(d)for(k(d),b=b.getNextSourceNode(!0,CKEDITOR.NODE_ELEMENT);b&&!b.equals(d);)if(b.isReadOnly()){if(b.getPosition(d)&CKEDITOR.POSITION_CONTAINS)break;b=b.getNext(p)}else k=b.getNextSourceNode(!1,CKEDITOR.NODE_ELEMENT),"img"==b.getName()&&b.data("cke-realelement")||!f(a,b)||(h.test(b.getName())?
 b.remove(1):(b.removeAttributes(e),a.fire("removeFormatCleanup",b))),b=k;c.moveToBookmark(l)}a.forceNextSelectionCheck();a.getSelection().selectRanges(m)}}},filter:function(a,h){for(var e=a._.removeFormatFilters||[],f=0;f<e.length;f++)if(!1===e[f](h))return!1;return!0}};CKEDITOR.editor.prototype.addRemoveFormatFilter=function(a){this._.removeFormatFilters||(this._.removeFormatFilters=[]);this._.removeFormatFilters.push(a)};CKEDITOR.config.removeFormatTags="b,big,cite,code,del,dfn,em,font,i,ins,kbd,q,s,samp,small,span,strike,strong,sub,sup,tt,u,var";
-CKEDITOR.config.removeFormatAttributes="class,style,lang,width,height,align,hspace,valign";CKEDITOR.plugins.add("resize",{init:function(b){function f(d){var e=c.width,m=c.height,f=e+(d.data.$.screenX-n.x)*("rtl"==g?-1:1);d=m+(d.data.$.screenY-n.y);h&&(e=Math.max(a.resize_minWidth,Math.min(f,a.resize_maxWidth)));p&&(m=Math.max(a.resize_minHeight,Math.min(d,a.resize_maxHeight)));b.resize(h?e:null,m)}function k(){CKEDITOR.document.removeListener("mousemove",f);CKEDITOR.document.removeListener("mouseup",k);b.document&&(b.document.removeListener("mousemove",f),b.document.removeListener("mouseup",
-k))}var a=b.config,r=b.ui.spaceId("resizer"),g=b.element?b.element.getDirection(1):"ltr";!a.resize_dir&&(a.resize_dir="vertical");void 0===a.resize_maxWidth&&(a.resize_maxWidth=3E3);void 0===a.resize_maxHeight&&(a.resize_maxHeight=3E3);void 0===a.resize_minWidth&&(a.resize_minWidth=750);void 0===a.resize_minHeight&&(a.resize_minHeight=250);if(!1!==a.resize_enabled){var l=null,n,c,h=("both"==a.resize_dir||"horizontal"==a.resize_dir)&&a.resize_minWidth!=a.resize_maxWidth,p=("both"==a.resize_dir||"vertical"==
-a.resize_dir)&&a.resize_minHeight!=a.resize_maxHeight,q=CKEDITOR.tools.addFunction(function(d){l||(l=b.getResizable());c={width:l.$.offsetWidth||0,height:l.$.offsetHeight||0};n={x:d.screenX,y:d.screenY};a.resize_minWidth>c.width&&(a.resize_minWidth=c.width);a.resize_minHeight>c.height&&(a.resize_minHeight=c.height);CKEDITOR.document.on("mousemove",f);CKEDITOR.document.on("mouseup",k);b.document&&(b.document.on("mousemove",f),b.document.on("mouseup",k));d.preventDefault&&d.preventDefault()});b.on("destroy",
-function(){CKEDITOR.tools.removeFunction(q)});b.on("uiSpace",function(a){if("bottom"==a.data.space){var e="";h&&!p&&(e=" cke_resizer_horizontal");!h&&p&&(e=" cke_resizer_vertical");var c='\x3cspan id\x3d"'+r+'" class\x3d"cke_resizer'+e+" cke_resizer_"+g+'" title\x3d"'+CKEDITOR.tools.htmlEncode(b.lang.common.resize)+'" onmousedown\x3d"CKEDITOR.tools.callFunction('+q+', event)"\x3e'+("ltr"==g?"◢":"◣")+"\x3c/span\x3e";"ltr"==g&&"ltr"==e?a.data.html+=c:a.data.html=c+a.data.html}},b,null,100);b.on("maximize",
-function(a){b.ui.space("resizer")[a.data==CKEDITOR.TRISTATE_ON?"hide":"show"]()})}}});CKEDITOR.config.plugins='basicstyles,notification,button,toolbar,clipboard,enterkey,entities,floatingspace,wysiwygarea,indent,indentlist,dialogui,dialog,fakeobjects,link,list,removeformat,resize';CKEDITOR.config.skin='moono-lisa';(function() {var setIcons = function(icons, strip) {var path = CKEDITOR.getUrl( 'plugins/' + strip );icons = icons.split( ',' );for ( var i = 0; i < icons.length; i++ )CKEDITOR.skin.icons[ icons[ i ] ] = { path: path, offset: -icons[ ++i ], bgsize : icons[ ++i ] };};if (CKEDITOR.env.hidpi) setIcons('bold,0,,italic,24,,strike,48,,subscript,72,,superscript,96,,underline,120,,copy-rtl,144,,copy,168,,cut-rtl,192,,cut,216,,paste-rtl,240,,paste,264,,indent-rtl,288,,indent,312,,outdent-rtl,336,,outdent,360,,anchor-rtl,384,,anchor,408,,link,432,,unlink,456,,bulletedlist-rtl,480,,bulletedlist,504,,numberedlist-rtl,528,,numberedlist,552,,removeformat,576,','icons_hidpi.png');else setIcons('bold,0,auto,italic,24,auto,strike,48,auto,subscript,72,auto,superscript,96,auto,underline,120,auto,copy-rtl,144,auto,copy,168,auto,cut-rtl,192,auto,cut,216,auto,paste-rtl,240,auto,paste,264,auto,indent-rtl,288,auto,indent,312,auto,outdent-rtl,336,auto,outdent,360,auto,anchor-rtl,384,auto,anchor,408,auto,link,432,auto,unlink,456,auto,bulletedlist-rtl,480,auto,bulletedlist,504,auto,numberedlist-rtl,528,auto,numberedlist,552,auto,removeformat,576,auto','icons.png');})();CKEDITOR.lang.languages={"en":1,"de":1};}());
\ No newline at end of file
+CKEDITOR.config.removeFormatAttributes="class,style,lang,width,height,align,hspace,valign";CKEDITOR.plugins.add("sourcedialog",{requires:"dialog",init:function(a){a.addCommand("sourcedialog",new CKEDITOR.dialogCommand("sourcedialog"));CKEDITOR.dialog.add("sourcedialog",this.path+"dialogs/sourcedialog.js");a.ui.addButton&&a.ui.addButton("Sourcedialog",{label:a.lang.sourcedialog.toolbar,command:"sourcedialog",toolbar:"mode,10"})}});CKEDITOR.config.plugins='basicstyles,notification,button,toolbar,clipboard,enterkey,entities,floatingspace,horizontalrule,indent,indentlist,dialogui,dialog,fakeobjects,link,list,removeformat,sourcedialog';CKEDITOR.config.skin='moono-lisa';(function() {var setIcons = function(icons, strip) {var path = CKEDITOR.getUrl( 'plugins/' + strip );icons = icons.split( ',' );for ( var i = 0; i < icons.length; i++ )CKEDITOR.skin.icons[ icons[ i ] ] = { path: path, offset: -icons[ ++i ], bgsize : icons[ ++i ] };};if (CKEDITOR.env.hidpi) setIcons('bold,0,,italic,24,,strike,48,,subscript,72,,superscript,96,,underline,120,,copy-rtl,144,,copy,168,,cut-rtl,192,,cut,216,,paste-rtl,240,,paste,264,,horizontalrule,288,,indent-rtl,312,,indent,336,,outdent-rtl,360,,outdent,384,,anchor-rtl,408,,anchor,432,,link,456,,unlink,480,,bulletedlist-rtl,504,,bulletedlist,528,,numberedlist-rtl,552,,numberedlist,576,,removeformat,600,,sourcedialog-rtl,624,,sourcedialog,648,','icons_hidpi.png');else setIcons('bold,0,auto,italic,24,auto,strike,48,auto,subscript,72,auto,superscript,96,auto,underline,120,auto,copy-rtl,144,auto,copy,168,auto,cut-rtl,192,auto,cut,216,auto,paste-rtl,240,auto,paste,264,auto,horizontalrule,288,auto,indent-rtl,312,auto,indent,336,auto,outdent-rtl,360,auto,outdent,384,auto,anchor-rtl,408,auto,anchor,432,auto,link,456,auto,unlink,480,auto,bulletedlist-rtl,504,auto,bulletedlist,528,auto,numberedlist-rtl,552,auto,numberedlist,576,auto,removeformat,600,auto,sourcedialog-rtl,624,auto,sourcedialog,648,auto','icons.png');})();CKEDITOR.lang.languages={"en":1,"de":1};}());
index 9db2eed..13c398a 100644 (file)
@@ -4,6 +4,6 @@
  */
 
 CKEDITOR.editorConfig = function( config ) {
-       // Dialog windows are also simplified.
-       config.removeDialogTabs = 'link:advanced';
+       // Simplify the dialog windows.
+       config.removeDialogTabs = 'image:advanced;link:advanced';
 };
index 6ce868f..cf8a6d9 100644 (file)
@@ -2,4 +2,4 @@
 Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.md or http://ckeditor.com/license\r
 */
-CKEDITOR.lang['de']={"editor":"WYSIWYG-Editor","editorPanel":"WYSIWYG-Editor-Leiste","common":{"editorHelp":"Drücken Sie ALT 0 für Hilfe","browseServer":"Server durchsuchen","url":"URL","protocol":"Protokoll","upload":"Hochladen","uploadSubmit":"Zum Server senden","image":"Bild","flash":"Flash","form":"Formular","checkbox":"Kontrollbox","radio":"Optionsfeld","textField":"Textfeld","textarea":"Textfeld","hiddenField":"Verstecktes Feld","button":"Schaltfläche","select":"Auswahlfeld","imageButton":"Bildschaltfläche","notSet":"<nicht festgelegt>","id":"Kennung","name":"Name","langDir":"Schreibrichtung","langDirLtr":"Links nach Rechts (LTR)","langDirRtl":"Rechts nach Links (RTL)","langCode":"Sprachcode","longDescr":"Langbeschreibungs-URL","cssClass":"Formatvorlagenklassen","advisoryTitle":"Titel Beschreibung","cssStyle":"Stil","ok":"OK","cancel":"Abbrechen","close":"Schließen","preview":"Vorschau","resize":"Größe ändern","generalTab":"Allgemein","advancedTab":"Erweitert","validateNumberFailed":"Dieser Wert ist keine Nummer.","confirmNewPage":"Alle nicht gespeicherten Änderungen gehen verloren. Sind Sie sicher die neue Seite zu laden?","confirmCancel":"Einige Optionen wurden geändert. Wollen Sie den Dialog dennoch schließen?","options":"Optionen","target":"Zielseite","targetNew":"Neues Fenster (_blank)","targetTop":"Oberstes Fenster (_top)","targetSelf":"Gleiches Fenster (_self)","targetParent":"Oberes Fenster (_parent)","langDirLTR":"Links nach Rechts (LNR)","langDirRTL":"Rechts nach Links (RNL)","styles":"Style","cssClasses":"Stylesheet Klasse","width":"Breite","height":"Höhe","align":"Ausrichtung","alignLeft":"Links","alignRight":"Rechts","alignCenter":"Zentriert","alignJustify":"Blocksatz","alignTop":"Oben","alignMiddle":"Mitte","alignBottom":"Unten","alignNone":"Keine","invalidValue":"Ungültiger Wert.","invalidHeight":"Höhe muss eine Zahl sein.","invalidWidth":"Breite muss eine Zahl sein.","invalidCssLength":"Wert spezifiziert für \"%1\" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).","invalidHtmlLength":"Wert spezifiziert für \"%1\" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte HTML Messeinheit (px oder %).","invalidInlineStyle":"Wert spezifiziert für inline Stilart muss enthalten ein oder mehr Tupels mit dem Format \"Name : Wert\" getrennt mit Semikolons.","cssLengthTooltip":"Gebe eine Zahl ein für ein Wert in pixels oder eine Zahl mit einer korrekten CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).","unavailable":"%1<span class=\"cke_accessibility\">, nicht verfügbar</span>","keyboard":{"8":"Rücktaste","13":"Eingabe","16":"Umschalt","17":"Strg","18":"Alt","32":"Leer","35":"Ende","36":"Pos1","46":"Entfernen","224":"Befehl"},"keyboardShortcut":"Tastaturkürzel"},"basicstyles":{"bold":"Fett","italic":"Kursiv","strike":"Durchgestrichen","subscript":"Tiefgestellt","superscript":"Hochgestellt","underline":"Unterstrichen"},"notification":{"closed":"Benachrichtigung geschlossen."},"button":{"selectedLabel":"%1 (Ausgewählt)"},"toolbar":{"toolbarCollapse":"Werkzeugleiste einklappen","toolbarExpand":"Werkzeugleiste ausklappen","toolbarGroups":{"document":"Dokument","clipboard":"Zwischenablage/Rückgängig","editing":"Editieren","forms":"Formulare","basicstyles":"Grundstile","paragraph":"Absatz","links":"Links","insert":"Einfügen","styles":"Stile","colors":"Farben","tools":"Werkzeuge"},"toolbars":"Editor Werkzeugleisten"},"clipboard":{"copy":"Kopieren","copyError":"Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).","cut":"Ausschneiden","cutError":"Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch auszuschneiden. Bitte benutzen Sie die System-Zwischenablage über STRG-X (ausschneiden) und STRG-V (einfügen).","paste":"Einfügen","pasteNotification":"Ihr Browser verhindert das Einfügen über diesen Weg. Zum einfügen drücken Sie %1."},"indent":{"indent":"Einzug erhöhen","outdent":"Einzug verringern"},"fakeobjects":{"anchor":"Anker","flash":"Flash-Animation","hiddenfield":"Verstecktes Feld","iframe":"IFrame","unknown":"Unbekanntes Objekt"},"link":{"acccessKey":"Zugriffstaste","advanced":"Erweitert","advisoryContentType":"Inhaltstyp","advisoryTitle":"Titel Beschreibung","anchor":{"toolbar":"Anker","menu":"Anker bearbeiten","title":"Ankereigenschaften","name":"Ankername","errorName":"Bitte geben Sie den Namen des Ankers ein","remove":"Anker entfernen"},"anchorId":"Nach Elementkennung","anchorName":"Nach Ankername","charset":"Verknüpfter Ressourcenzeichensatz","cssClasses":"Formatvorlagenklasse","download":"Herunterladen erzwingen","displayText":"Anzeigetext","emailAddress":"E-Mail-Adresse","emailBody":"Nachrichtentext","emailSubject":"Betreffzeile","id":"Kennung","info":"Linkinfo","langCode":"Sprachcode","langDir":"Schreibrichtung","langDirLTR":"Links nach Rechts (LTR)","langDirRTL":"Rechts nach Links (RTL)","menu":"Link bearbeiten","name":"Name","noAnchors":"(Keine Anker im Dokument vorhanden)","noEmail":"Bitte geben Sie E-Mail-Adresse an","noUrl":"Bitte geben Sie die Link-URL an","other":"<andere>","popupDependent":"Abhängig (Netscape)","popupFeatures":"Pop-up Fenstereigenschaften","popupFullScreen":"Vollbild (IE)","popupLeft":"Linke Position","popupLocationBar":"Adressleiste","popupMenuBar":"Menüleiste","popupResizable":"Größe änderbar","popupScrollBars":"Rollbalken","popupStatusBar":"Statusleiste","popupToolbar":"Werkzeugleiste","popupTop":"Obere Position","rel":"Beziehung","selectAnchor":"Anker auswählen","styles":"Style","tabIndex":"Tab-Index","target":"Zielseite","targetFrame":"<Frame>","targetFrameName":"Ziel-Fenster-Name","targetPopup":"<Pop-up Fenster>","targetPopupName":"Pop-up Fenster-Name","title":"Link","toAnchor":"Anker in dieser Seite","toEmail":"E-Mail","toUrl":"URL","toolbar":"Link einfügen/editieren","type":"Link-Typ","unlink":"Link entfernen","upload":"Hochladen"},"list":{"bulletedlist":"Liste","numberedlist":"Nummerierte Liste einfügen/entfernen"},"removeformat":{"toolbar":"Formatierung entfernen"}};
\ No newline at end of file
+CKEDITOR.lang['de']={"editor":"WYSIWYG-Editor","editorPanel":"WYSIWYG-Editor-Leiste","common":{"editorHelp":"Drücken Sie ALT 0 für Hilfe","browseServer":"Server durchsuchen","url":"URL","protocol":"Protokoll","upload":"Hochladen","uploadSubmit":"Zum Server senden","image":"Bild","flash":"Flash","form":"Formular","checkbox":"Kontrollbox","radio":"Optionsfeld","textField":"Textfeld","textarea":"Textfeld","hiddenField":"Verstecktes Feld","button":"Schaltfläche","select":"Auswahlfeld","imageButton":"Bildschaltfläche","notSet":"<nicht festgelegt>","id":"Kennung","name":"Name","langDir":"Schreibrichtung","langDirLtr":"Links nach Rechts (LTR)","langDirRtl":"Rechts nach Links (RTL)","langCode":"Sprachcode","longDescr":"Langbeschreibungs-URL","cssClass":"Formatvorlagenklassen","advisoryTitle":"Titel Beschreibung","cssStyle":"Stil","ok":"OK","cancel":"Abbrechen","close":"Schließen","preview":"Vorschau","resize":"Größe ändern","generalTab":"Allgemein","advancedTab":"Erweitert","validateNumberFailed":"Dieser Wert ist keine Nummer.","confirmNewPage":"Alle nicht gespeicherten Änderungen gehen verloren. Sind Sie sicher die neue Seite zu laden?","confirmCancel":"Einige Optionen wurden geändert. Wollen Sie den Dialog dennoch schließen?","options":"Optionen","target":"Zielseite","targetNew":"Neues Fenster (_blank)","targetTop":"Oberstes Fenster (_top)","targetSelf":"Gleiches Fenster (_self)","targetParent":"Oberes Fenster (_parent)","langDirLTR":"Links nach Rechts (LNR)","langDirRTL":"Rechts nach Links (RNL)","styles":"Style","cssClasses":"Stylesheet Klasse","width":"Breite","height":"Höhe","align":"Ausrichtung","alignLeft":"Links","alignRight":"Rechts","alignCenter":"Zentriert","alignJustify":"Blocksatz","alignTop":"Oben","alignMiddle":"Mitte","alignBottom":"Unten","alignNone":"Keine","invalidValue":"Ungültiger Wert.","invalidHeight":"Höhe muss eine Zahl sein.","invalidWidth":"Breite muss eine Zahl sein.","invalidCssLength":"Wert spezifiziert für \"%1\" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).","invalidHtmlLength":"Wert spezifiziert für \"%1\" Feld muss ein positiver numerischer Wert sein mit oder ohne korrekte HTML Messeinheit (px oder %).","invalidInlineStyle":"Wert spezifiziert für inline Stilart muss enthalten ein oder mehr Tupels mit dem Format \"Name : Wert\" getrennt mit Semikolons.","cssLengthTooltip":"Gebe eine Zahl ein für ein Wert in pixels oder eine Zahl mit einer korrekten CSS Messeinheit (px, %, in, cm, mm, em, ex, pt oder pc).","unavailable":"%1<span class=\"cke_accessibility\">, nicht verfügbar</span>","keyboard":{"8":"Rücktaste","13":"Eingabe","16":"Umschalt","17":"Strg","18":"Alt","32":"Leer","35":"Ende","36":"Pos1","46":"Entfernen","224":"Befehl"},"keyboardShortcut":"Tastaturkürzel"},"basicstyles":{"bold":"Fett","italic":"Kursiv","strike":"Durchgestrichen","subscript":"Tiefgestellt","superscript":"Hochgestellt","underline":"Unterstrichen"},"notification":{"closed":"Benachrichtigung geschlossen."},"button":{"selectedLabel":"%1 (Ausgewählt)"},"toolbar":{"toolbarCollapse":"Werkzeugleiste einklappen","toolbarExpand":"Werkzeugleiste ausklappen","toolbarGroups":{"document":"Dokument","clipboard":"Zwischenablage/Rückgängig","editing":"Editieren","forms":"Formulare","basicstyles":"Grundstile","paragraph":"Absatz","links":"Links","insert":"Einfügen","styles":"Stile","colors":"Farben","tools":"Werkzeuge"},"toolbars":"Editor Werkzeugleisten"},"clipboard":{"copy":"Kopieren","copyError":"Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).","cut":"Ausschneiden","cutError":"Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch auszuschneiden. Bitte benutzen Sie die System-Zwischenablage über STRG-X (ausschneiden) und STRG-V (einfügen).","paste":"Einfügen","pasteNotification":"Ihr Browser verhindert das Einfügen über diesen Weg. Zum einfügen drücken Sie %1."},"horizontalrule":{"toolbar":"Horizontale Linie einfügen"},"indent":{"indent":"Einzug erhöhen","outdent":"Einzug verringern"},"fakeobjects":{"anchor":"Anker","flash":"Flash-Animation","hiddenfield":"Verstecktes Feld","iframe":"IFrame","unknown":"Unbekanntes Objekt"},"link":{"acccessKey":"Zugriffstaste","advanced":"Erweitert","advisoryContentType":"Inhaltstyp","advisoryTitle":"Titel Beschreibung","anchor":{"toolbar":"Anker","menu":"Anker bearbeiten","title":"Ankereigenschaften","name":"Ankername","errorName":"Bitte geben Sie den Namen des Ankers ein","remove":"Anker entfernen"},"anchorId":"Nach Elementkennung","anchorName":"Nach Ankername","charset":"Verknüpfter Ressourcenzeichensatz","cssClasses":"Formatvorlagenklasse","download":"Herunterladen erzwingen","displayText":"Anzeigetext","emailAddress":"E-Mail-Adresse","emailBody":"Nachrichtentext","emailSubject":"Betreffzeile","id":"Kennung","info":"Linkinfo","langCode":"Sprachcode","langDir":"Schreibrichtung","langDirLTR":"Links nach Rechts (LTR)","langDirRTL":"Rechts nach Links (RTL)","menu":"Link bearbeiten","name":"Name","noAnchors":"(Keine Anker im Dokument vorhanden)","noEmail":"Bitte geben Sie E-Mail-Adresse an","noUrl":"Bitte geben Sie die Link-URL an","other":"<andere>","popupDependent":"Abhängig (Netscape)","popupFeatures":"Pop-up Fenstereigenschaften","popupFullScreen":"Vollbild (IE)","popupLeft":"Linke Position","popupLocationBar":"Adressleiste","popupMenuBar":"Menüleiste","popupResizable":"Größe änderbar","popupScrollBars":"Rollbalken","popupStatusBar":"Statusleiste","popupToolbar":"Werkzeugleiste","popupTop":"Obere Position","rel":"Beziehung","selectAnchor":"Anker auswählen","styles":"Style","tabIndex":"Tab-Index","target":"Zielseite","targetFrame":"<Frame>","targetFrameName":"Ziel-Fenster-Name","targetPopup":"<Pop-up Fenster>","targetPopupName":"Pop-up Fenster-Name","title":"Link","toAnchor":"Anker in dieser Seite","toEmail":"E-Mail","toUrl":"URL","toolbar":"Link einfügen/editieren","type":"Link-Typ","unlink":"Link entfernen","upload":"Hochladen"},"list":{"bulletedlist":"Liste","numberedlist":"Nummerierte Liste einfügen/entfernen"},"removeformat":{"toolbar":"Formatierung entfernen"},"sourcedialog":{"toolbar":"Quellcode","title":"Quellcode"}};
\ No newline at end of file
index c3817f3..897fa47 100644 (file)
@@ -2,4 +2,4 @@
 Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.md or http://ckeditor.com/license\r
 */
-CKEDITOR.lang['en']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Press ALT 0 for help","browseServer":"Browse Server","url":"URL","protocol":"Protocol","upload":"Upload","uploadSubmit":"Send it to the Server","image":"Image","flash":"Flash","form":"Form","checkbox":"Checkbox","radio":"Radio Button","textField":"Text Field","textarea":"Textarea","hiddenField":"Hidden Field","button":"Button","select":"Selection Field","imageButton":"Image Button","notSet":"<not set>","id":"Id","name":"Name","langDir":"Language Direction","langDirLtr":"Left to Right (LTR)","langDirRtl":"Right to Left (RTL)","langCode":"Language Code","longDescr":"Long Description URL","cssClass":"Stylesheet Classes","advisoryTitle":"Advisory Title","cssStyle":"Style","ok":"OK","cancel":"Cancel","close":"Close","preview":"Preview","resize":"Resize","generalTab":"General","advancedTab":"Advanced","validateNumberFailed":"This value is not a number.","confirmNewPage":"Any unsaved changes to this content will be lost. Are you sure you want to load new page?","confirmCancel":"You have changed some options. Are you sure you want to close the dialog window?","options":"Options","target":"Target","targetNew":"New Window (_blank)","targetTop":"Topmost Window (_top)","targetSelf":"Same Window (_self)","targetParent":"Parent Window (_parent)","langDirLTR":"Left to Right (LTR)","langDirRTL":"Right to Left (RTL)","styles":"Style","cssClasses":"Stylesheet Classes","width":"Width","height":"Height","align":"Alignment","alignLeft":"Left","alignRight":"Right","alignCenter":"Center","alignJustify":"Justify","alignTop":"Top","alignMiddle":"Middle","alignBottom":"Bottom","alignNone":"None","invalidValue":"Invalid value.","invalidHeight":"Height must be a number.","invalidWidth":"Width must be a number.","invalidCssLength":"Value specified for the \"%1\" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"Value specified for the \"%1\" field must be a positive number with or without a valid HTML measurement unit (px or %).","invalidInlineStyle":"Value specified for the inline style must consist of one or more tuples with the format of \"name : value\", separated by semi-colons.","cssLengthTooltip":"Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, unavailable</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","224":"Command"},"keyboardShortcut":"Keyboard shortcut"},"basicstyles":{"bold":"Bold","italic":"Italic","strike":"Strikethrough","subscript":"Subscript","superscript":"Superscript","underline":"Underline"},"notification":{"closed":"Notification closed."},"button":{"selectedLabel":"%1 (Selected)"},"toolbar":{"toolbarCollapse":"Collapse Toolbar","toolbarExpand":"Expand Toolbar","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"Editor toolbars"},"clipboard":{"copy":"Copy","copyError":"Your browser security settings don't permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).","cut":"Cut","cutError":"Your browser security settings don't permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).","paste":"Paste","pasteNotification":"Your browser doesn't allow you to paste this way. Press %1 to paste."},"indent":{"indent":"Increase Indent","outdent":"Decrease Indent"},"fakeobjects":{"anchor":"Anchor","flash":"Flash Animation","hiddenfield":"Hidden Field","iframe":"IFrame","unknown":"Unknown Object"},"link":{"acccessKey":"Access Key","advanced":"Advanced","advisoryContentType":"Advisory Content Type","advisoryTitle":"Advisory Title","anchor":{"toolbar":"Anchor","menu":"Edit Anchor","title":"Anchor Properties","name":"Anchor Name","errorName":"Please type the anchor name","remove":"Remove Anchor"},"anchorId":"By Element Id","anchorName":"By Anchor Name","charset":"Linked Resource Charset","cssClasses":"Stylesheet Classes","download":"Force Download","displayText":"Display Text","emailAddress":"E-Mail Address","emailBody":"Message Body","emailSubject":"Message Subject","id":"Id","info":"Link Info","langCode":"Language Code","langDir":"Language Direction","langDirLTR":"Left to Right (LTR)","langDirRTL":"Right to Left (RTL)","menu":"Edit Link","name":"Name","noAnchors":"(No anchors available in the document)","noEmail":"Please type the e-mail address","noUrl":"Please type the link URL","other":"<other>","popupDependent":"Dependent (Netscape)","popupFeatures":"Popup Window Features","popupFullScreen":"Full Screen (IE)","popupLeft":"Left Position","popupLocationBar":"Location Bar","popupMenuBar":"Menu Bar","popupResizable":"Resizable","popupScrollBars":"Scroll Bars","popupStatusBar":"Status Bar","popupToolbar":"Toolbar","popupTop":"Top Position","rel":"Relationship","selectAnchor":"Select an Anchor","styles":"Style","tabIndex":"Tab Index","target":"Target","targetFrame":"<frame>","targetFrameName":"Target Frame Name","targetPopup":"<popup window>","targetPopupName":"Popup Window Name","title":"Link","toAnchor":"Link to anchor in the text","toEmail":"E-mail","toUrl":"URL","toolbar":"Link","type":"Link Type","unlink":"Unlink","upload":"Upload"},"list":{"bulletedlist":"Insert/Remove Bulleted List","numberedlist":"Insert/Remove Numbered List"},"removeformat":{"toolbar":"Remove Format"}};
\ No newline at end of file
+CKEDITOR.lang['en']={"editor":"Rich Text Editor","editorPanel":"Rich Text Editor panel","common":{"editorHelp":"Press ALT 0 for help","browseServer":"Browse Server","url":"URL","protocol":"Protocol","upload":"Upload","uploadSubmit":"Send it to the Server","image":"Image","flash":"Flash","form":"Form","checkbox":"Checkbox","radio":"Radio Button","textField":"Text Field","textarea":"Textarea","hiddenField":"Hidden Field","button":"Button","select":"Selection Field","imageButton":"Image Button","notSet":"<not set>","id":"Id","name":"Name","langDir":"Language Direction","langDirLtr":"Left to Right (LTR)","langDirRtl":"Right to Left (RTL)","langCode":"Language Code","longDescr":"Long Description URL","cssClass":"Stylesheet Classes","advisoryTitle":"Advisory Title","cssStyle":"Style","ok":"OK","cancel":"Cancel","close":"Close","preview":"Preview","resize":"Resize","generalTab":"General","advancedTab":"Advanced","validateNumberFailed":"This value is not a number.","confirmNewPage":"Any unsaved changes to this content will be lost. Are you sure you want to load new page?","confirmCancel":"You have changed some options. Are you sure you want to close the dialog window?","options":"Options","target":"Target","targetNew":"New Window (_blank)","targetTop":"Topmost Window (_top)","targetSelf":"Same Window (_self)","targetParent":"Parent Window (_parent)","langDirLTR":"Left to Right (LTR)","langDirRTL":"Right to Left (RTL)","styles":"Style","cssClasses":"Stylesheet Classes","width":"Width","height":"Height","align":"Alignment","alignLeft":"Left","alignRight":"Right","alignCenter":"Center","alignJustify":"Justify","alignTop":"Top","alignMiddle":"Middle","alignBottom":"Bottom","alignNone":"None","invalidValue":"Invalid value.","invalidHeight":"Height must be a number.","invalidWidth":"Width must be a number.","invalidCssLength":"Value specified for the \"%1\" field must be a positive number with or without a valid CSS measurement unit (px, %, in, cm, mm, em, ex, pt, or pc).","invalidHtmlLength":"Value specified for the \"%1\" field must be a positive number with or without a valid HTML measurement unit (px or %).","invalidInlineStyle":"Value specified for the inline style must consist of one or more tuples with the format of \"name : value\", separated by semi-colons.","cssLengthTooltip":"Enter a number for a value in pixels or a number with a valid CSS unit (px, %, in, cm, mm, em, ex, pt, or pc).","unavailable":"%1<span class=\"cke_accessibility\">, unavailable</span>","keyboard":{"8":"Backspace","13":"Enter","16":"Shift","17":"Ctrl","18":"Alt","32":"Space","35":"End","36":"Home","46":"Delete","224":"Command"},"keyboardShortcut":"Keyboard shortcut"},"basicstyles":{"bold":"Bold","italic":"Italic","strike":"Strikethrough","subscript":"Subscript","superscript":"Superscript","underline":"Underline"},"notification":{"closed":"Notification closed."},"button":{"selectedLabel":"%1 (Selected)"},"toolbar":{"toolbarCollapse":"Collapse Toolbar","toolbarExpand":"Expand Toolbar","toolbarGroups":{"document":"Document","clipboard":"Clipboard/Undo","editing":"Editing","forms":"Forms","basicstyles":"Basic Styles","paragraph":"Paragraph","links":"Links","insert":"Insert","styles":"Styles","colors":"Colors","tools":"Tools"},"toolbars":"Editor toolbars"},"clipboard":{"copy":"Copy","copyError":"Your browser security settings don't permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).","cut":"Cut","cutError":"Your browser security settings don't permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).","paste":"Paste","pasteNotification":"Your browser doesn't allow you to paste this way. Press %1 to paste."},"horizontalrule":{"toolbar":"Insert Horizontal Line"},"indent":{"indent":"Increase Indent","outdent":"Decrease Indent"},"fakeobjects":{"anchor":"Anchor","flash":"Flash Animation","hiddenfield":"Hidden Field","iframe":"IFrame","unknown":"Unknown Object"},"link":{"acccessKey":"Access Key","advanced":"Advanced","advisoryContentType":"Advisory Content Type","advisoryTitle":"Advisory Title","anchor":{"toolbar":"Anchor","menu":"Edit Anchor","title":"Anchor Properties","name":"Anchor Name","errorName":"Please type the anchor name","remove":"Remove Anchor"},"anchorId":"By Element Id","anchorName":"By Anchor Name","charset":"Linked Resource Charset","cssClasses":"Stylesheet Classes","download":"Force Download","displayText":"Display Text","emailAddress":"E-Mail Address","emailBody":"Message Body","emailSubject":"Message Subject","id":"Id","info":"Link Info","langCode":"Language Code","langDir":"Language Direction","langDirLTR":"Left to Right (LTR)","langDirRTL":"Right to Left (RTL)","menu":"Edit Link","name":"Name","noAnchors":"(No anchors available in the document)","noEmail":"Please type the e-mail address","noUrl":"Please type the link URL","other":"<other>","popupDependent":"Dependent (Netscape)","popupFeatures":"Popup Window Features","popupFullScreen":"Full Screen (IE)","popupLeft":"Left Position","popupLocationBar":"Location Bar","popupMenuBar":"Menu Bar","popupResizable":"Resizable","popupScrollBars":"Scroll Bars","popupStatusBar":"Status Bar","popupToolbar":"Toolbar","popupTop":"Top Position","rel":"Relationship","selectAnchor":"Select an Anchor","styles":"Style","tabIndex":"Tab Index","target":"Target","targetFrame":"<frame>","targetFrameName":"Target Frame Name","targetPopup":"<popup window>","targetPopupName":"Popup Window Name","title":"Link","toAnchor":"Link to anchor in the text","toEmail":"E-mail","toUrl":"URL","toolbar":"Link","type":"Link Type","unlink":"Unlink","upload":"Upload"},"list":{"bulletedlist":"Insert/Remove Bulleted List","numberedlist":"Insert/Remove Numbered List"},"removeformat":{"toolbar":"Remove Format"},"sourcedialog":{"toolbar":"Source","title":"Source"}};
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/css/codemirror.min.css b/js/ckeditor/plugins/codemirror/css/codemirror.min.css
new file mode 100644 (file)
index 0000000..dfd7af0
--- /dev/null
@@ -0,0 +1 @@
+.CodeMirror{font-family:monospace;height:300px;color:black}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{background-color:white}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:black}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid black;border-right:0;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:-20px;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:blue}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:bold}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3,.cm-s-default .cm-type{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:#f00}.cm-invalidchar{color:#f00}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:white}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-vscrollbar,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:none!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:transparent;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-scroll,.CodeMirror-sizer,.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0}.CodeMirror{font:13px/1.4em monospace;text-align:left}.CodeMirror .activeline{background:#e8f2ff}.CodeMirror .CodeMirror-foldmarker{color:blue;-ms-text-shadow:#b9f 1px 1px 2px,#b9f -1px -1px 2px,#b9f 1px -1px 2px,#b9f -1px 1px 2px;-webkit-text-shadow:#b9f 1px 1px 2px,#b9f -1px -1px 2px,#b9f 1px -1px 2px,#b9f -1px 1px 2px;text-shadow:#b9f 1px 1px 2px,#b9f -1px -1px 2px,#b9f 1px -1px 2px,#b9f -1px 1px 2px;font-family:arial;line-height:.3;cursor:pointer}.CodeMirror-matchingtag{background:#ff9600;background:rgba(255,150,0,0.3)}.searchCodeButton span,.autoFormat span,.CommentSelectedRange span,.UncommentSelectedRange span{width:16px;height:16px;margin-left:6px}.searchCodeButton span{background:url("../icons/searchcode.png") no-repeat}.autoFormat span{background:url("../icons/autoformat.png") no-repeat}.CommentSelectedRange span{background:url("../icons/commentselectedrange.png") no-repeat}.UncommentSelectedRange span{background:url("../icons/uncommentselectedrange.png") no-repeat}.cke_reset_all .CodeMirror-scroll *{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.cke_reset_all .cm-s-cobalt *,.cke_reset_all .cm-s-erlang-dark *,.cke_reset_all .cm-s-lesser-dark *,.cke_reset_all .cm-s-monokai *,.cke_reset_all .cm-s-night *,.cke_reset_all .cm-s-rubyblue *,.cke_reset_all .cm-s-twilight *,.cke_reset_all .cm-s-xq-dark *,.cke_reset_all .cm-s-base16-dark *,.cke_reset_all .cm-s-3024-night *,.cke_reset_all .cm-s-the-matrix *,.cke_reset_all .cm-s-paraiso-dark *,.cke_reset_all .cm-s-paraiso-light *{color:inherit;font:inherit}.cm-s-cobalt .CodeMirror-selected{background:#b36539!important}.cm-s-erlang-dark .CodeMirror-selected{background:#b36539!important}.cm-s-lesser-dark .CodeMirror-selected{background:#45443b!important}.cm-s-monokai .CodeMirror-selected{background:#49483e!important}.cm-s-night .CodeMirror-selected{background:#447!important}.cm-s-rubyblue .CodeMirror-selected{background:#38566f!important}.cm-s-twilight .CodeMirror-selected{background:#323232!important}.cm-s-xq-dark .CodeMirror-selected{background:#a8f!important}.cm-s-the-matrix .CodeMirror-selected{background:#494949!important}.cm-s-mbo .CodeMirror-selected{background:#716c62!important}.cm-s-blackboard .activeline,.cm-s-cobalt .activeline,.cm-s-erlang-dark .activeline,.cm-s-lesser-dark .activeline,.cm-s-monokai .activeline,.cm-s-night .activeline,.cm-s-rubyblue .activeline,.cm-s-vibrant-ink .activeline,.cm-s-xq-dark .activeline,.cm-s-base16-dark .activeline,.cm-s-3024-night .activeline,.cm-s-paraiso-light .activeline,.cm-s-paraiso-dark .activeline,.cm-s-pastel-on-dark .activeline{background:#757575}.cm-s-pastel-on-dark .activeline{background:#404040}.cm-s-mbo .activeline{background:#716c62}.cm-s-twilight .activeline{background:#494949}.cm-s-the-matrix .activeline{background:#060}.CodeMirror-focused .cm-matchhighlight{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);background-position:bottom;background-repeat:repeat-x}.CodeMirror-hints{position:absolute;z-index:10;overflow:hidden;list-style:none;margin:0;padding:2px;-webkit-box-shadow:2px 3px 5px #000;-ms-box-shadow:2px 3px 5px #000;box-shadow:2px 3px 5px #000;border-radius:3px;border:1px solid silver;background:white;font-size:90%;font-family:monospace;max-height:20em;overflow-y:auto}.CodeMirror-hint{margin:0;padding:0 4px;border-radius:2px;max-width:19em;overflow:hidden;white-space:pre;color:black;cursor:pointer}.CodeMirror-hint-active{background:#08f;color:white}.cm-trailingspace{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==);background-position:bottom left;background-repeat:repeat-x}.CodeMirror-dialog{position:absolute;left:0;right:0;background:inherit;z-index:15;padding:.1em .8em;overflow:hidden;color:inherit}.CodeMirror-dialog-top{border-bottom:1px solid #eee;top:0}.CodeMirror-dialog-bottom{border-top:1px solid #eee;bottom:0}.CodeMirror-dialog input{border:0;outline:0;background:transparent;width:20em;color:inherit;font-family:monospace}.CodeMirror-dialog button{font-size:70%}.CodeMirror-foldmarker{color:blue;text-shadow:#b9f 1px 1px 2px,#b9f -1px -1px 2px,#b9f 1px -1px 2px,#b9f -1px 1px 2px;font-family:arial;line-height:.3;cursor:pointer}.CodeMirror-foldgutter{width:.7em}.CodeMirror-foldgutter-open,.CodeMirror-foldgutter-folded{cursor:pointer}.CodeMirror-foldgutter-open:after{content:"\25BE"}.CodeMirror-foldgutter-folded:after{content:"\25B8"}\r
diff --git a/js/ckeditor/plugins/codemirror/js/beautify.min.js b/js/ckeditor/plugins/codemirror/js/beautify.min.js
new file mode 100644 (file)
index 0000000..33cdfb6
--- /dev/null
@@ -0,0 +1,75 @@
+!function(){function f(a,l){for(var d=0;d<l.length;d+=1)if(l[d]===a)return!0;return!1}function x(a,l){return(new I(a,l)).beautify()}function I(r,l){function w(c,b){var e=0;return c&&(e=c.indentation_level,!g.just_added_newline()&&c.line_indent_level>e&&(e=c.line_indent_level)),{mode:b,parent:c,last_text:c?c.last_text:"",last_word:c?c.last_word:"",declaration_statement:!1,declaration_assignment:!1,multiline_frame:!1,if_block:!1,else_block:!1,do_block:!1,do_while:!1,in_case_statement:!1,in_case:!1,
+case_body:!1,indentation_level:e,line_indent_level:c?c.line_indent_level:e,start_line_index:g.get_line_number(),ternary_depth:0}}function p(b){var e=b.newlines;if(m.keep_array_indentation&&c.mode===a.ArrayLiteral)for(g=0;g<e;g+=1)q(0<g);else if(m.max_preserve_newlines&&e>m.max_preserve_newlines&&(e=m.max_preserve_newlines),m.preserve_newlines&&1<b.newlines){q();for(var g=1;g<e;g+=1)q(!0)}h=b;O[h.type]()}function B(c){(c=void 0!==c&&c,g.just_added_newline())||(m.preserve_newlines&&h.wanted_newline||
+c?q(!1,!0):m.wrap_line_length&&g.current_line.get_character_count()+h.text.length+(g.space_before_token?1:0)>=m.wrap_line_length&&q(!1,!0))}function q(b,e){if(!e&&";"!==c.last_text&&","!==c.last_text&&"\x3d"!==c.last_text&&"TK_OPERATOR"!==k)for(;c.mode===a.Statement&&!c.if_block&&!c.do_block;)z();g.add_new_line(b)&&(c.multiline_frame=!0)}function K(){g.just_added_newline()&&(m.keep_array_indentation&&c.mode===a.ArrayLiteral&&h.wanted_newline?(g.current_line.push(h.whitespace_before),g.space_before_token=
+!1):g.set_indent(c.indentation_level)&&(c.line_indent_level=c.indentation_level))}function t(c){if(g.raw)return void g.add_raw_token(h);m.comma_first&&"TK_COMMA"===k&&g.just_added_newline()&&","===g.previous_line.last()&&(g.previous_line.pop(),K(),g.add_token(","),g.space_before_token=!0);c=c||h.text;K();g.add_token(c)}function D(b){c?(N.push(c),e=c):e=w(null,b);c=w(e,b)}function E(c){return f(c,[a.Expression,a.ForInitializer,a.Conditional])}function z(){0<N.length&&(e=c,c=N.pop(),e.mode===a.Statement&&
+g.remove_redundant_indentation(e))}function C(){return c.parent.mode===a.ObjectLiteral&&c.mode===a.Statement&&(":"===c.last_text&&0===c.ternary_depth||"TK_RESERVED"===k&&f(c.last_text,["get","set"]))}function b(){var b;if(b=!!("TK_RESERVED"===k&&f(c.last_text,["var","let","const"])&&"TK_WORD"===h.type||"TK_RESERVED"===k&&"do"===c.last_text||"TK_RESERVED"===k&&"return"===c.last_text&&!h.wanted_newline||"TK_RESERVED"===k&&"else"===c.last_text&&("TK_RESERVED"!==h.type||"if"!==h.text)||"TK_END_EXPR"===
+k&&(e.mode===a.ForInitializer||e.mode===a.Conditional)||"TK_WORD"===k&&c.mode===a.BlockStatement&&!c.in_case&&"--"!==h.text&&"++"!==h.text&&"function"!==G&&"TK_WORD"!==h.type&&"TK_RESERVED"!==h.type||c.mode===a.ObjectLiteral&&(":"===c.last_text&&0===c.ternary_depth||"TK_RESERVED"===k&&f(c.last_text,["get","set"]))))D(a.Statement),c.indentation_level+=1,b=("TK_RESERVED"===k&&f(c.last_text,["var","let","const"])&&"TK_WORD"===h.type&&(c.declaration_statement=!0),C()||B("TK_RESERVED"===h.type&&f(h.text,
+["do","for","if","while"])),!0);return b}function u(c){return f(c,"case return do if throw else".split(" "))}function y(c){c=L+(c||0);return 0>c||c>=x.length?null:x[c]}function F(){("TK_RESERVED"===h.type&&c.mode!==a.ObjectLiteral&&f(h.text,["set","get"])&&(h.type="TK_WORD"),"TK_RESERVED"===h.type&&c.mode===a.ObjectLiteral)&&":"==y(1).text&&(h.type="TK_WORD");if(b()||!h.wanted_newline||E(c.mode)||"TK_OPERATOR"===k&&"--"!==c.last_text&&"++"!==c.last_text||"TK_EQUALS"===k||!m.preserve_newlines&&"TK_RESERVED"===
+k&&f(c.last_text,["var","let","const","set","get"])||q(),c.do_block&&!c.do_while){if("TK_RESERVED"===h.type&&"while"===h.text)return g.space_before_token=!0,t(),g.space_before_token=!0,void(c.do_while=!0);q();c.do_block=!1}if(c.if_block)if(c.else_block||"TK_RESERVED"!==h.type||"else"!==h.text){for(;c.mode===a.Statement;)z();c.if_block=!1;c.else_block=!1}else c.else_block=!0;if("TK_RESERVED"===h.type&&("case"===h.text||"default"===h.text&&c.in_case_statement)){q();if(c.case_body||m.jslint_happy)0<
+c.indentation_level&&(!c.parent||c.indentation_level>c.parent.indentation_level)&&--c.indentation_level,c.case_body=!1;return t(),c.in_case=!0,void(c.in_case_statement=!0)}if("TK_RESERVED"===h.type&&"function"===h.text&&((f(c.last_text,["}",";"])||g.just_added_newline()&&!f(c.last_text,["[","{",":","\x3d",","]))&&(g.just_added_blankline()||h.comments_before.length||(q(),q(!0))),"TK_RESERVED"===k||"TK_WORD"===k?"TK_RESERVED"===k&&f(c.last_text,"get set new return export async".split(" "))?g.space_before_token=
+!0:"TK_RESERVED"===k&&"default"===c.last_text&&"export"===G?g.space_before_token=!0:q():"TK_OPERATOR"===k||"\x3d"===c.last_text?g.space_before_token=!0:(c.multiline_frame||!E(c.mode)&&c.mode!==a.ArrayLiteral)&&q()),"TK_COMMA"!==k&&"TK_START_EXPR"!==k&&"TK_EQUALS"!==k&&"TK_OPERATOR"!==k||C()||B(),"TK_RESERVED"===h.type&&f(h.text,["function","get","set"]))return t(),void(c.last_word=h.text);(v="NONE","TK_END_BLOCK"===k?"TK_RESERVED"===h.type&&f(h.text,["else","catch","finally"])?"expand"===m.brace_style||
+"end-expand"===m.brace_style||"none"===m.brace_style&&h.wanted_newline?v="NEWLINE":(v="SPACE",g.space_before_token=!0):v="NEWLINE":"TK_SEMICOLON"===k&&c.mode===a.BlockStatement?v="NEWLINE":"TK_SEMICOLON"===k&&E(c.mode)?v="SPACE":"TK_STRING"===k?v="NEWLINE":"TK_RESERVED"===k||"TK_WORD"===k||"*"===c.last_text&&"function"===G?v="SPACE":"TK_START_BLOCK"===k?v="NEWLINE":"TK_END_EXPR"===k&&(g.space_before_token=!0,v="NEWLINE"),"TK_RESERVED"===h.type&&f(h.text,H.line_starters)&&")"!==c.last_text&&(v="else"===
+c.last_text||"export"===c.last_text?"SPACE":"NEWLINE"),"TK_RESERVED"===h.type&&f(h.text,["else","catch","finally"]))?"TK_END_BLOCK"!==k||"expand"===m.brace_style||"end-expand"===m.brace_style||"none"===m.brace_style&&h.wanted_newline?q():(g.trim(!0),"}"!==g.current_line.last()&&q(),g.space_before_token=!0):"NEWLINE"===v?"TK_RESERVED"===k&&u(c.last_text)?g.space_before_token=!0:"TK_END_EXPR"!==k?"TK_START_EXPR"===k&&"TK_RESERVED"===h.type&&f(h.text,["var","let","const"])||":"===c.last_text||("TK_RESERVED"===
+h.type&&"if"===h.text&&"else"===c.last_text?g.space_before_token=!0:q()):"TK_RESERVED"===h.type&&f(h.text,H.line_starters)&&")"!==c.last_text&&q():c.multiline_frame&&c.mode===a.ArrayLiteral&&","===c.last_text&&"}"===G?q():"SPACE"===v&&(g.space_before_token=!0);t();c.last_word=h.text;"TK_RESERVED"===h.type&&"do"===h.text&&(c.do_block=!0);"TK_RESERVED"===h.type&&"if"===h.text&&(c.if_block=!0)}var g,L,H,h,k,G,n,c,e,N,v,O,m,x=[],J="";O={TK_START_EXPR:function(){b();var e=a.Expression;if("["===h.text){if("TK_WORD"===
+k||")"===c.last_text)return"TK_RESERVED"===k&&f(c.last_text,H.line_starters)&&(g.space_before_token=!0),D(e),t(),c.indentation_level+=1,void(m.space_in_paren&&(g.space_before_token=!0));e=a.ArrayLiteral;c.mode===a.ArrayLiteral&&("["!==c.last_text&&(","!==c.last_text||"]"!==G&&"}"!==G)||m.keep_array_indentation||q())}else"TK_RESERVED"===k&&"for"===c.last_text?e=a.ForInitializer:"TK_RESERVED"===k&&f(c.last_text,["if","while"])&&(e=a.Conditional);";"===c.last_text||"TK_START_BLOCK"===k?q():"TK_END_EXPR"===
+k||"TK_START_EXPR"===k||"TK_END_BLOCK"===k||"."===c.last_text?B(h.wanted_newline):"TK_RESERVED"===k&&"("===h.text||"TK_WORD"===k||"TK_OPERATOR"===k?"TK_RESERVED"===k&&("function"===c.last_word||"typeof"===c.last_word)||"*"===c.last_text&&"function"===G?m.space_after_anon_function&&(g.space_before_token=!0):"TK_RESERVED"!==k||!f(c.last_text,H.line_starters)&&"catch"!==c.last_text||m.space_before_conditional&&(g.space_before_token=!0):g.space_before_token=!0;"("===h.text&&"TK_RESERVED"===k&&"await"===
+c.last_word&&(g.space_before_token=!0);"("===h.text&&("TK_EQUALS"!==k&&"TK_OPERATOR"!==k||C()||B());D(e);t();m.space_in_paren&&(g.space_before_token=!0);c.indentation_level+=1},TK_END_EXPR:function(){for(;c.mode===a.Statement;)z();c.multiline_frame&&B("]"===h.text&&c.mode===a.ArrayLiteral&&!m.keep_array_indentation);m.space_in_paren&&("TK_START_EXPR"!==k||m.space_in_empty_paren?g.space_before_token=!0:(g.trim(),g.space_before_token=!1));"]"===h.text&&m.keep_array_indentation?(t(),z()):(z(),t());g.remove_redundant_indentation(e);
+c.do_while&&e.mode===a.Conditional&&(e.mode=a.Expression,c.do_block=!1,c.do_while=!1)},TK_START_BLOCK:function(){var b=y(1),r=y(2);D(r&&(":"===r.text&&f(b.type,["TK_STRING","TK_WORD","TK_RESERVED"])||f(b.text,["get","set"])&&f(r.type,["TK_WORD","TK_RESERVED"]))?f(G,["class","interface"])?a.BlockStatement:a.ObjectLiteral:a.BlockStatement);b=!b.comments_before.length&&"}"===b.text&&"function"===c.last_word&&"TK_END_EXPR"===k;"expand"===m.brace_style||"none"===m.brace_style&&h.wanted_newline?"TK_OPERATOR"!==
+k&&(b||"TK_EQUALS"===k||"TK_RESERVED"===k&&u(c.last_text)&&"else"!==c.last_text)?g.space_before_token=!0:q(!1,!0):"TK_OPERATOR"!==k&&"TK_START_EXPR"!==k?"TK_START_BLOCK"===k?q():g.space_before_token=!0:e.mode===a.ArrayLiteral&&","===c.last_text&&("}"===G?g.space_before_token=!0:q());t();c.indentation_level+=1},TK_END_BLOCK:function(){for(;c.mode===a.Statement;)z();var b="TK_START_BLOCK"===k;"expand"===m.brace_style?b||q():b||(c.mode===a.ArrayLiteral&&m.keep_array_indentation?(m.keep_array_indentation=
+!1,q(),m.keep_array_indentation=!0):q());z();t()},TK_WORD:F,TK_RESERVED:F,TK_SEMICOLON:function(){for(b()&&(g.space_before_token=!1);c.mode===a.Statement&&!c.if_block&&!c.do_block;)z();t()},TK_STRING:function(){b()?g.space_before_token=!0:"TK_RESERVED"===k||"TK_WORD"===k?g.space_before_token=!0:"TK_COMMA"===k||"TK_START_EXPR"===k||"TK_EQUALS"===k||"TK_OPERATOR"===k?C()||B():q();t()},TK_EQUALS:function(){b();c.declaration_statement&&(c.declaration_assignment=!0);g.space_before_token=!0;t();g.space_before_token=
+!0},TK_OPERATOR:function(){if(b(),"TK_RESERVED"===k&&u(c.last_text))return g.space_before_token=!0,void t();if("*"===h.text&&"TK_DOT"===k)return void t();if(":"===h.text&&c.in_case)return c.case_body=!0,c.indentation_level+=1,t(),q(),void(c.in_case=!1);if("::"===h.text)return void t();"TK_OPERATOR"===k&&B();var e=!0,y=!0;f(h.text,["--","++","!","~"])||f(h.text,["-","+"])&&(f(k,["TK_START_BLOCK","TK_START_EXPR","TK_EQUALS","TK_OPERATOR"])||f(c.last_text,H.line_starters)||","===c.last_text)?(e=!1,y=
+!1,!h.wanted_newline||"--"!==h.text&&"++"!==h.text||q(!1,!0),";"===c.last_text&&E(c.mode)&&(e=!0),"TK_RESERVED"===k?e=!0:"TK_END_EXPR"===k?e=!("]"===c.last_text&&("--"===h.text||"++"===h.text)):"TK_OPERATOR"===k&&(e=f(h.text,["--","-","++","+"])&&f(c.last_text,["--","-","++","+"]),f(h.text,["+","-"])&&f(c.last_text,["--","++"])&&(y=!0)),c.mode!==a.BlockStatement&&c.mode!==a.Statement||"{"!==c.last_text&&";"!==c.last_text||q()):":"===h.text?0===c.ternary_depth?e=!1:--c.ternary_depth:"?"===h.text?c.ternary_depth+=
+1:"*"===h.text&&"TK_RESERVED"===k&&"function"===c.last_text&&(e=!1,y=!1);g.space_before_token=g.space_before_token||e;t();g.space_before_token=y},TK_COMMA:function(){if(c.declaration_statement)return E(c.parent.mode)&&(c.declaration_assignment=!1),t(),void(c.declaration_assignment?(c.declaration_assignment=!1,q(!1,!0)):(g.space_before_token=!0,m.comma_first&&B()));t();c.mode===a.ObjectLiteral||c.mode===a.Statement&&c.parent.mode===a.ObjectLiteral?(c.mode===a.Statement&&z(),q()):(g.space_before_token=
+!0,m.comma_first&&B())},TK_BLOCK_COMMENT:function(){if(g.raw)return g.add_raw_token(h),void(h.directives&&"end"===h.directives.preserve&&(m.test_output_raw||(g.raw=!1)));if(h.directives)return q(!1,!0),t(),"start"===h.directives.preserve&&(g.raw=!0),void q(!1,!0);if(!A.newline.test(h.text)&&!h.wanted_newline)return g.space_before_token=!0,t(),void(g.space_before_token=!0);var c,b;b=h.text;b=b.replace(/\x0d/g,"");for(var e=[],a=b.indexOf("\n");-1!==a;)e.push(b.substring(0,a)),b=b.substring(a+1),a=
+b.indexOf("\n");b=(b.length&&e.push(b),e);var a=e=!1,y=h.whitespace_before,r=y.length;q(!1,!0);if(1<b.length){var k;a:{k=b.slice(1);for(var F=0;F<k.length;F++)if("*"!==k[F].replace(/^\s+|\s+$/g,"").charAt(0)){k=!1;break a}k=!0}if(k)e=!0;else{a:{k=b.slice(1);for(var F=0,l=k.length;F<l;F++)if((c=k[F])&&0!==c.indexOf(y)){c=!1;break a}c=!0}c&&(a=!0)}}t(b[0]);for(c=1;c<b.length;c++)q(!1,!0),e?t(" "+b[c].replace(/^\s+/g,"")):a&&b[c].length>r?t(b[c].substring(r)):g.add_token(b[c]);q(!1,!0)},TK_COMMENT:function(){h.wanted_newline?
+q(!1,!0):g.trim(!0);g.space_before_token=!0;t();q(!1,!0)},TK_DOT:function(){b();"TK_RESERVED"===k&&u(c.last_text)?g.space_before_token=!0:B(")"===c.last_text&&m.break_chained_methods);t()},TK_UNKNOWN:function(){t();"\n"===h.text[h.text.length-1]&&q()},TK_EOF:function(){for(;c.mode===a.Statement;)z()}};l=l||{};m={};void 0!==l.braces_on_own_line&&(m.brace_style=l.braces_on_own_line?"expand":"collapse");m.brace_style=l.brace_style?l.brace_style:m.brace_style?m.brace_style:"collapse";"expand-strict"===
+m.brace_style&&(m.brace_style="expand");m.indent_size=l.indent_size?parseInt(l.indent_size,10):4;m.indent_char=l.indent_char?l.indent_char:" ";m.eol=l.eol?l.eol:"\n";m.preserve_newlines=void 0===l.preserve_newlines||l.preserve_newlines;m.break_chained_methods=void 0!==l.break_chained_methods&&l.break_chained_methods;m.max_preserve_newlines=void 0===l.max_preserve_newlines?0:parseInt(l.max_preserve_newlines,10);m.space_in_paren=void 0!==l.space_in_paren&&l.space_in_paren;m.space_in_empty_paren=void 0!==
+l.space_in_empty_paren&&l.space_in_empty_paren;m.jslint_happy=void 0!==l.jslint_happy&&l.jslint_happy;m.space_after_anon_function=void 0!==l.space_after_anon_function&&l.space_after_anon_function;m.keep_array_indentation=void 0!==l.keep_array_indentation&&l.keep_array_indentation;m.space_before_conditional=void 0===l.space_before_conditional||l.space_before_conditional;m.unescape_strings=void 0!==l.unescape_strings&&l.unescape_strings;m.wrap_line_length=void 0===l.wrap_line_length?0:parseInt(l.wrap_line_length,
+10);m.e4x=void 0!==l.e4x&&l.e4x;m.end_with_newline=void 0!==l.end_with_newline&&l.end_with_newline;m.comma_first=void 0!==l.comma_first&&l.comma_first;m.test_output_raw=void 0!==l.test_output_raw&&l.test_output_raw;m.jslint_happy&&(m.space_after_anon_function=!0);l.indent_with_tabs&&(m.indent_char="\t",m.indent_size=1);m.eol=m.eol.replace(/\\r/,"\r").replace(/\\n/,"\n");for(n="";0<m.indent_size;)n+=m.indent_char,--m.indent_size;var M=0;if(r&&r.length){for(;" "===r.charAt(M)||"\t"===r.charAt(M);)J+=
+r.charAt(M),M+=1;r=r.substring(M)}k="TK_START_BLOCK";G="";g=new d(n,J);g.raw=m.test_output_raw;N=[];D(a.BlockStatement);this.beautify=function(){var b,e;H=new P(r,m,n);x=H.tokenize();for(L=0;b=y();){for(var a=0;a<b.comments_before.length;a++)p(b.comments_before[a]);p(b);G=c.last_text;k=b.type;c.last_text=b.text;L+=1}return e=g.get_code(),m.end_with_newline&&(e+="\n"),"\n"!=m.eol&&(e=e.replace(/[\n]/g,m.eol)),e}}function K(a){var l=0,d=-1,p=[],f=!0;this.set_indent=function(p){l=a.baseIndentLength+
+p*a.indent_length;d=p};this.get_character_count=function(){return l};this.is_empty=function(){return f};this.last=function(){return this._empty?null:p[p.length-1]};this.push=function(a){p.push(a);l+=a.length;f=!1};this.pop=function(){var a=null;return f||(a=p.pop(),l-=a.length,f=0===p.length),a};this.remove_indent=function(){0<d&&(--d,l-=a.indent_length)};this.trim=function(){for(;" "===this.last();)p.pop(),--l;f=0===p.length};this.toString=function(){var l="";return this._empty||(0<=d&&(l=a.indent_cache[d]),
+l+=p.join("")),l}}function d(r,l){l=l||"";this.indent_cache=[l];this.baseIndentLength=l.length;this.indent_length=r.length;this.raw=!1;var d=[];this.baseIndentString=l;this.indent_string=r;this.current_line=this.previous_line=null;this.space_before_token=!1;this.add_outputline=function(){this.previous_line=this.current_line;this.current_line=new K(this);d.push(this.current_line)};this.add_outputline();this.get_line_number=function(){return d.length};this.add_new_line=function(a){return(1!==this.get_line_number()||
+!this.just_added_newline())&&!(!a&&this.just_added_newline())&&(this.raw||this.add_outputline(),!0)};this.get_code=function(){return d.join("\n").replace(/[\r\n\t ]+$/,"")};this.set_indent=function(a){if(1<d.length){for(;a>=this.indent_cache.length;)this.indent_cache.push(this.indent_cache[this.indent_cache.length-1]+this.indent_string);return this.current_line.set_indent(a),!0}return this.current_line.set_indent(0),!1};this.add_raw_token=function(a){for(var r=0;r<a.newlines;r++)this.add_outputline();
+this.current_line.push(a.whitespace_before);this.current_line.push(a.text);this.space_before_token=!1};this.add_token=function(a){this.add_space_before_token();this.current_line.push(a)};this.add_space_before_token=function(){this.space_before_token&&!this.just_added_newline()&&this.current_line.push(" ");this.space_before_token=!1};this.remove_redundant_indentation=function(r){if(!r.multiline_frame&&r.mode!==a.ForInitializer&&r.mode!==a.Conditional){r=r.start_line_index;for(var l=d.length;r<l;)d[r].remove_indent(),
+r++}};this.trim=function(a){a=void 0!==a&&a;for(this.current_line.trim(r,l);a&&1<d.length&&this.current_line.is_empty();)d.pop(),this.current_line=d[d.length-1],this.current_line.trim();this.previous_line=1<d.length?d[d.length-2]:null};this.just_added_newline=function(){return this.current_line.is_empty()};this.just_added_blankline=function(){return this.just_added_newline()?1===d.length?!0:d[d.length-2].is_empty():!1}}function P(a,l,d){function p(){var d,n=[];if(D=0,E="",b>=u)return["","TK_EOF"];
+var c;c=C.length?C[C.length-1]:new J("TK_START_BLOCK","{");var e=a.charAt(b);for(b+=1;f(e,K);){if(A.newline.test(e)?"\n"===e&&"\r"===a.charAt(b-2)||(D+=1,n=[]):n.push(e),b>=u)return["","TK_EOF"];e=a.charAt(b);b+=1}if(n.length&&(E=n.join("")),q.test(e)){c=n=!0;var p=q;for("0"===e&&b<u&&/[Xx]/.test(a.charAt(b))?(n=!1,c=!1,e+=a.charAt(b),b+=1,p=x):(e="",--b);b<u&&p.test(a.charAt(b));)e+=a.charAt(b),b+=1,n&&b<u&&"."===a.charAt(b)&&(e+=a.charAt(b),b+=1,n=!1),c&&b<u&&/[Ee]/.test(a.charAt(b))&&(e+=a.charAt(b),
+b+=1,b<u&&/[+-]/.test(a.charAt(b))&&(e+=a.charAt(b),b+=1),c=!1,n=!1);return[e,"TK_WORD"]}if(A.isIdentifierStart(a.charCodeAt(b-1))){if(b<u)for(;A.isIdentifierChar(a.charCodeAt(b))&&(e+=a.charAt(b),(b+=1)!==u););return"TK_DOT"===c.type||"TK_RESERVED"===c.type&&f(c.text,["set","get"])||!f(e,y)?[e,"TK_WORD"]:"in"===e?[e,"TK_OPERATOR"]:[e,"TK_RESERVED"]}if("("===e||"["===e)return[e,"TK_START_EXPR"];if(")"===e||"]"===e)return[e,"TK_END_EXPR"];if("{"===e)return[e,"TK_START_BLOCK"];if("}"===e)return[e,"TK_END_BLOCK"];
+if(";"===e)return[e,"TK_SEMICOLON"];if("/"===e){n="";if("*"===a.charAt(b)){b+=1;F.lastIndex=b;e=F.exec(a);n="/*"+e[0];b+=e[0].length;c=n;if(c.match(L)){p={};H.lastIndex=0;for(d=H.exec(c);d;)p[d[1]]=d[2],d=H.exec(c);c=p}else c=null;return c&&"start"===c.ignore&&(h.lastIndex=b,e=h.exec(a),n+=e[0],b+=e[0].length),n=n.replace(A.lineBreak,"\n"),[n,"TK_BLOCK_COMMENT",c]}if("/"===a.charAt(b))return b+=1,g.lastIndex=b,e=g.exec(a),n="//"+e[0],b+=e[0].length,[n,"TK_COMMENT"]}if("`"===e||"'"===e||'"'===e||("/"===
+e||l.e4x&&"\x3c"===e&&a.slice(b-1).match(/^<([-a-zA-Z:0-9_.]+|{[^{}]*}|!\[CDATA\[[\s\S]*?\]\])(\s+[-a-zA-Z:0-9_.]+\s*=\s*('[^']*'|"[^"]*"|{.*?}))*\s*(\/?)\s*>/))&&("TK_RESERVED"===c.type&&f(c.text,"return case throw else do typeof yield".split(" "))||"TK_END_EXPR"===c.type&&")"===c.text&&c.parent&&"TK_RESERVED"===c.parent.type&&f(c.parent.text,["if","while","for"])||f(c.type,"TK_COMMENT TK_START_EXPR TK_START_BLOCK TK_END_BLOCK TK_OPERATOR TK_EQUALS TK_EOF TK_SEMICOLON TK_COMMA".split(" ")))){var n=
+e,v=c=!1;if(d=e,"/"===n)for(e=!1;b<u&&(c||e||a.charAt(b)!==n)&&!A.newline.test(a.charAt(b));)d+=a.charAt(b),c?c=!1:(c="\\"===a.charAt(b),"["===a.charAt(b)?e=!0:"]"===a.charAt(b)&&(e=!1)),b+=1;else if(l.e4x&&"\x3c"===n){if(c=/<(\/?)([-a-zA-Z:0-9_.]+|{[^{}]*}|!\[CDATA\[[\s\S]*?\]\])(\s+[-a-zA-Z:0-9_.]+\s*=\s*('[^']*'|"[^"]*"|{.*?}))*\s*(\/?)\s*>/g,e=a.slice(b-1),(p=c.exec(e))&&0===p.index){n=p[2];for(d=0;p;){var v=!!p[1],w=p[2],m=!!p[p.length-1]||"![CDATA["===w.slice(0,8);if(w!==n||m||(v?--d:++d),0>=
+d)break;p=c.exec(e)}n=p?p.index+p[0].length:e.length;return e=e.slice(0,n),b+=n-1,e=e.replace(A.lineBreak,"\n"),[e,"TK_STRING"]}}else for(;b<u&&(c||a.charAt(b)!==n&&("`"===n||!A.newline.test(a.charAt(b))));)(c||"`"===n)&&A.newline.test(a.charAt(b))?("\r"===a.charAt(b)&&"\n"===a.charAt(b+1)&&(b+=1),d+="\n"):d+=a.charAt(b),c?("x"!==a.charAt(b)&&"u"!==a.charAt(b)||(v=!0),c=!1):c="\\"===a.charAt(b),b+=1;if(v&&l.unescape_strings){a:{e=d;p=!1;d="";v=0;w="";for(m=0;p||v<e.length;)if(c=e.charAt(v),v++,p){if(p=
+!1,"x"===c)w=e.substr(v,2),v+=2;else{if("u"!==c){d+="\\"+c;continue}w=e.substr(v,4);v+=4}if(!w.match(/^[0123456789abcdefABCDEF]+$/))break a;if(0<=(m=parseInt(w,16))&&32>m)d+="x"===c?"\\x"+w:"\\u"+w;else if(34===m||39===m||92===m)d+="\\"+String.fromCharCode(m);else{if("x"===c&&126<m&&255>=m)break a;d+=String.fromCharCode(m)}}else"\\"===c?p=!0:d+=c;e=d}d=e}if(b<u&&a.charAt(b)===n&&(d+=n,b+=1,"/"===n))for(;b<u&&A.isIdentifierStart(a.charCodeAt(b));)d+=a.charAt(b),b+=1;return[d,"TK_STRING"]}if("#"===
+e){if(0===C.length&&"!"===a.charAt(b)){for(d=e;b<u&&"\n"!==e;)e=a.charAt(b),d+=e,b+=1;return[d.replace(/^\s+|\s+$/g,"")+"\n","TK_UNKNOWN"]}n="#";if(b<u&&q.test(a.charAt(b))){do e=a.charAt(b),n+=e,b+=1;while(b<u&&"#"!==e&&"\x3d"!==e);return"#"===e||("["===a.charAt(b)&&"]"===a.charAt(b+1)?(n+="[]",b+=2):"{"===a.charAt(b)&&"}"===a.charAt(b+1)&&(n+="{}",b+=2)),[n,"TK_WORD"]}}if("\x3c"===e&&("?"===a.charAt(b)||"%"===a.charAt(b))&&(k.lastIndex=b-1,n=k.exec(a)))return e=n[0],b+=e.length-1,e=e.replace(A.lineBreak,
+"\n"),[e,"TK_STRING"];if("\x3c"===e&&"\x3c!--"===a.substring(b-1,b+3)){b+=3;for(e="\x3c!--";!A.newline.test(a.charAt(b))&&b<u;)e+=a.charAt(b),b++;return z=!0,[e,"TK_COMMENT"]}if("-"===e&&z&&"--\x3e"===a.substring(b-1,b+2))return z=!1,b+=2,["--\x3e","TK_COMMENT"];if("."===e)return[e,"TK_DOT"];if(f(e,t)){for(;b<u&&f(e+a.charAt(b),t)&&(e+=a.charAt(b),!((b+=1)>=u)););return","===e?[e,"TK_COMMA"]:"\x3d"===e?[e,"TK_EQUALS"]:[e,"TK_OPERATOR"]}return[e,"TK_UNKNOWN"]}var K=["\n","\r","\t"," "],q=/[0-9]/,x=
+/[0123456789abcdefABCDEF]/,t="+ - * / % \x26 ++ -- \x3d +\x3d -\x3d *\x3d /\x3d %\x3d \x3d\x3d \x3d\x3d\x3d !\x3d !\x3d\x3d \x3e \x3c \x3e\x3d \x3c\x3d \x3e\x3e \x3c\x3c \x3e\x3e\x3e \x3e\x3e\x3e\x3d \x3e\x3e\x3d \x3c\x3c\x3d \x26\x26 \x26\x3d | || ! ~ , : ? ^ ^\x3d |\x3d :: \x3d\x3e \x3c%\x3d \x3c% %\x3e \x3c?\x3d \x3c? ?\x3e".split(" ");this.line_starters="continue try throw return var let const if switch case default for while break function import export".split(" ");var D,E,z,C,b,u,y=this.line_starters.concat("do in else get set new catch finally typeof yield async await".split(" ")),
+F=/([\s\S]*?)((?:\*\/)|$)/g,g=/([^\n\r\u2028\u2029]*)/g,L=/\/\* beautify( \w+[:]\w+)+ \*\//g,H=/ (\w+)[:](\w+)/g,h=/([\s\S]*?)((?:\/\*\sbeautify\signore:end\s\*\/)|$)/g,k=/((<\?php|<\?=)[\s\S]*?\?>)|(<%[\s\S]*?%>)/g;this.tokenize=function(){u=a.length;b=0;z=!1;C=[];for(var g,d,c,e=null,h=[],y=[];!d||"TK_EOF"!==d.type;){c=p();for(g=new J(c[1],c[0],D,E);"TK_COMMENT"===g.type||"TK_BLOCK_COMMENT"===g.type||"TK_UNKNOWN"===g.type;)"TK_BLOCK_COMMENT"===g.type&&(g.directives=c[2]),y.push(g),c=p(),g=new J(c[1],
+c[0],D,E);y.length&&(g.comments_before=y,y=[]);"TK_START_BLOCK"===g.type||"TK_START_EXPR"===g.type?(g.parent=d,h.push(e),e=g):("TK_END_BLOCK"===g.type||"TK_END_EXPR"===g.type)&&e&&("]"===g.text&&"["===e.text||")"===g.text&&"("===e.text||"}"===g.text&&"{"===e.text)&&(g.parent=e.parent,e=h.pop());C.push(g);d=g}return C}}var A={};!function(a){var d=RegExp("[ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԧԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠࢢ-ࢬऄ-हऽॐक़-ॡॱ-ॷॹ-ॿঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-ళవ-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛰᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤜᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々-〇〡-〩〱-〵〸-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚗꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞓꞠ-Ɦꟸ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꪀ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ]"),
+f=RegExp("[ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԧԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠࢢ-ࢬऄ-हऽॐक़-ॡॱ-ॷॹ-ॿঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-ళవ-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛰᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤜᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々-〇〡-〩〱-〵〸-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚗꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞓꞠ-Ɦꟸ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꪀ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ̀-ͯ҃-֑҇-ׇֽֿׁׂׅׄؐ-ؚؠ-ىٲ-ۓۧ-ۨۻ-ۼܰ-݊ࠀ-ࠔࠛ-ࠣࠥ-ࠧࠩ-࠭ࡀ-ࡗࣤ-ࣾऀ-ःऺ-़ा-ॏ॑-ॗॢ-ॣ०-९ঁ-ঃ়া-ৄেৈৗয়-ৠਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑ੦-ੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢ-ૣ૦-૯ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୟ-ୠ୦-୯ஂா-ூெ-ைொ-்ௗ௦-௯ఁ-ఃె-ైొ-్ౕౖౢ-ౣ౦-౯ಂಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢ-ೣ೦-೯ംഃെ-ൈൗൢ-ൣ൦-൯ංඃ්ා-ුූෘ-ෟෲෳิ-ฺเ-ๅ๐-๙ິ-ູ່-ໍ໐-໙༘༙༠-༩༹༵༷ཁ-ཇཱ-྄྆-྇ྍ-ྗྙ-ྼ࿆က-ဩ၀-၉ၧ-ၭၱ-ၴႂ-ႍႏ-ႝ፝-፟ᜎ-ᜐᜠ-ᜰᝀ-ᝐᝲᝳក-ឲ៝០-៩᠋-᠍᠐-᠙ᤠ-ᤫᤰ-᤻ᥑ-ᥭᦰ-ᧀᧈ-ᧉ᧐-᧙ᨀ-ᨕᨠ-ᩓ᩠-᩿᩼-᪉᪐-᪙ᭆ-ᭋ᭐-᭙᭫-᭳᮰-᮹᯦-᯳ᰀ-ᰢ᱀-᱉ᱛ-ᱽ᳐-᳒ᴀ-ᶾḁ-ἕ‌‍‿⁀⁔⃐-⃥⃜⃡-⃰ⶁ-ⶖⷠ-ⷿ〡-〨゙゚Ꙁ-ꙭꙴ-꙽ꚟ꛰-꛱ꟸ-ꠀ꠆ꠋꠣ-ꠧꢀ-ꢁꢴ-꣄꣐-꣙ꣳ-ꣷ꤀-꤉ꤦ-꤭ꤰ-ꥅꦀ-ꦃ꦳-꧀ꨀ-ꨧꩀ-ꩁꩌ-ꩍ꩐-꩙ꩻꫠ-ꫩꫲ-ꫳꯀ-ꯡ꯬꯭꯰-꯹ﬠ-ﬨ︀-️︠-︦︳︴﹍-﹏0-9_]");
+a.newline=/[\n\r\u2028\u2029]/;a.lineBreak=/\r\n|[\n\r\u2028\u2029]/g;a.isIdentifierStart=function(a){return 65>a?36===a:91>a||(97>a?95===a:123>a||170<=a&&d.test(String.fromCharCode(a)))};a.isIdentifierChar=function(a){return 48>a?36===a:58>a||!(65>a)&&(91>a||(97>a?95===a:123>a||170<=a&&f.test(String.fromCharCode(a))))}}(A);var a={BlockStatement:"BlockStatement",Statement:"Statement",ObjectLiteral:"ObjectLiteral",ArrayLiteral:"ArrayLiteral",ForInitializer:"ForInitializer",Conditional:"Conditional",
+Expression:"Expression"},J=function(a,d,f,p,K,q){this.type=a;this.text=d;this.comments_before=[];this.newlines=f||0;this.wanted_newline=0<f;this.whitespace_before=p||"";this.directives=this.parent=null};"function"==typeof define&&define.amd?define("beautify.js",[],function(){return{js_beautify:x}}):"undefined"!=typeof exports?exports.js_beautify=x:"undefined"!=typeof window?window.js_beautify=x:"undefined"!=typeof global&&(global.js_beautify=x)}();
+(function(){function f(f,d,x,A){var a,J,r,l,w,p,B,q,I,t,D,E,z,C,b;d=d||{};void 0!==d.wrap_line_length&&0!==parseInt(d.wrap_line_length,10)||void 0===d.max_char||0===parseInt(d.max_char,10)||(d.wrap_line_length=d.max_char);J=void 0!==d.indent_inner_html&&d.indent_inner_html;r=void 0===d.indent_size?4:parseInt(d.indent_size,10);l=void 0===d.indent_char?" ":d.indent_char;p=void 0===d.brace_style?"collapse":d.brace_style;w=0===parseInt(d.wrap_line_length,10)?32786:parseInt(d.wrap_line_length||250,10);
+B=d.unformatted||"a span img bdo em strong dfn code samp kbd var cite abbr acronym q sub sup tt i b big small u s strike font ins del pre address dt h1 h2 h3 h4 h5 h6".split(" ");I=(q=void 0===d.preserve_newlines||d.preserve_newlines)?isNaN(parseInt(d.max_preserve_newlines,10))?32786:parseInt(d.max_preserve_newlines,10):0;t=void 0!==d.indent_handlebars&&d.indent_handlebars;D=void 0===d.wrap_attributes?"auto":d.wrap_attributes;E=void 0===d.wrap_attributes_indent_size?r:parseInt(d.wrap_attributes_indent_size,
+10)||r;z=void 0!==d.end_with_newline&&d.end_with_newline;C="object"==typeof d.extra_liners&&d.extra_liners?d.extra_liners.concat():"string"==typeof d.extra_liners?d.extra_liners.split(","):["head","body","/html"];b=d.eol?d.eol:"\n";d.indent_with_tabs&&(l="\t",r=1);b=b.replace(/\\r/,"\r").replace(/\\n/,"\n");a=new function(){return this.pos=0,this.token="",this.current_mode="CONTENT",this.tags={parent:"parent1",parentcount:1,parent1:""},this.tag_type="",this.token_text=this.last_token=this.last_text=
+this.token_type="",this.newlines=0,this.indent_content=J,this.Utils={whitespace:["\n","\r","\t"," "],single_token:"br input link meta source !doctype basefont base area hr wbr param img isindex embed".split(" "),extra_liners:C,in_array:function(a,b){for(var g=0;g<b.length;g++)if(a===b[g])return!0;return!1}},this.is_whitespace=function(a){for(;0<a.length;a++)if(!this.Utils.in_array(a.charAt(0),this.Utils.whitespace))return!1;return!0},this.traverse_whitespace=function(){var a="";if(a=this.input.charAt(this.pos),
+this.Utils.in_array(a,this.Utils.whitespace)){for(this.newlines=0;this.Utils.in_array(a,this.Utils.whitespace);)q&&"\n"===a&&this.newlines<=I&&(this.newlines+=1),this.pos++,a=this.input.charAt(this.pos);return!0}return!1},this.space_or_wrap=function(a){this.line_char_count>=this.wrap_line_length?(this.print_newline(!1,a),this.print_indentation(a)):(this.line_char_count++,a.push(" "))},this.get_content=function(){for(var a="",b=[];"\x3c"!==this.input.charAt(this.pos);){if(this.pos>=this.input.length)return b.length?
+b.join(""):["","TK_EOF"];if(this.traverse_whitespace())this.space_or_wrap(b);else{if(t){a=this.input.substr(this.pos,3);if("{{#"===a||"{{/"===a)break;if("{{!"===a)return[this.get_tag(),"TK_TAG_HANDLEBARS_COMMENT"];if("{{"===this.input.substr(this.pos,2)&&"{{else}}"===this.get_tag(!0))break}a=this.input.charAt(this.pos);this.pos++;this.line_char_count++;b.push(a)}}return b.length?b.join(""):""},this.get_contents_to=function(a){if(this.pos===this.input.length)return["","TK_EOF"];var b="";a=new RegExp("\x3c/"+
+a+"\\s*\x3e","igm");a.lastIndex=this.pos;a=(a=a.exec(this.input))?a.index:this.input.length;return this.pos<a&&(b=this.input.substring(this.pos,a),this.pos=a),b},this.record_tag=function(a){this.tags[a+"count"]?(this.tags[a+"count"]++,this.tags[a+this.tags[a+"count"]]=this.indent_level):(this.tags[a+"count"]=1,this.tags[a+this.tags[a+"count"]]=this.indent_level);this.tags[a+this.tags[a+"count"]+"parent"]=this.tags.parent;this.tags.parent=a+this.tags[a+"count"]},this.retrieve_tag=function(a){if(this.tags[a+
+"count"]){for(var b=this.tags.parent;b&&a+this.tags[a+"count"]!==b;)b=this.tags[b+"parent"];b&&(this.indent_level=this.tags[a+this.tags[a+"count"]],this.tags.parent=this.tags[b+"parent"]);delete this.tags[a+this.tags[a+"count"]+"parent"];delete this.tags[a+this.tags[a+"count"]];1===this.tags[a+"count"]?delete this.tags[a+"count"]:this.tags[a+"count"]--}},this.indent_to_tag=function(a){if(this.tags[a+"count"]){for(var b=this.tags.parent;b&&a+this.tags[a+"count"]!==b;)b=this.tags[b+"parent"];b&&(this.indent_level=
+this.tags[a+this.tags[a+"count"]])}},this.get_tag=function(a){var b,g,d="",f=[],h="",k=!1,p=!0,n=this.pos,c=this.line_char_count;a=void 0!==a&&a;do{if(this.pos>=this.input.length)return a&&(this.pos=n,this.line_char_count=c),f.length?f.join(""):["","TK_EOF"];if(d=this.input.charAt(this.pos),this.pos++,this.Utils.in_array(d,this.Utils.whitespace))k=!0;else{if("'"!==d&&'"'!==d||(d+=this.get_unformatted(d),k=!0),"\x3d"===d&&(k=!1),f.length&&"\x3d"!==f[f.length-1]&&"\x3e"!==d&&k){if(this.space_or_wrap(f),
+k=!1,!p&&"force"===D&&"/"!==d){this.print_newline(!0,f);this.print_indentation(f);for(var e=0;e<E;e++)f.push(l)}for(e=0;e<f.length;e++)if(" "===f[e]){p=!1;break}}if(t&&"\x3c"===g&&"{{"===d+this.input.charAt(this.pos)&&(d+=this.get_unformatted("}}"),f.length&&" "!==f[f.length-1]&&"\x3c"!==f[f.length-1]&&(d=" "+d),k=!0),"\x3c"!==d||g||(b=this.pos-1,g="\x3c"),t&&!g&&2<=f.length&&"{"===f[f.length-1]&&"{"===f[f.length-2]&&(b="#"===d||"/"===d||"!"===d?this.pos-3:this.pos-2,g="{"),this.line_char_count++,
+f.push(d),f[1]&&("!"===f[1]||"?"===f[1]||"%"===f[1])){f=[this.get_comment(b)];break}if(t&&f[1]&&"{"===f[1]&&f[2]&&"!"===f[2]){f=[this.get_comment(b)];break}if(t&&"{"===g&&2<f.length&&"}"===f[f.length-2]&&"}"===f[f.length-1])break}}while("\x3e"!==d);b=f.join("");g=-1!==b.indexOf(" ")?b.indexOf(" "):"{"===b.charAt(0)?b.indexOf("}"):b.indexOf("\x3e");d="\x3c"!==b.charAt(0)&&t?"#"===b.charAt(2)?3:2:1;g=b.substring(d,g).toLowerCase();return"/"===b.charAt(b.length-2)||this.Utils.in_array(g,this.Utils.single_token)?
+a||(this.tag_type="SINGLE"):t&&"{"===b.charAt(0)&&"else"===g?a||(this.indent_to_tag("if"),this.tag_type="HANDLEBARS_ELSE",this.indent_content=!0,this.traverse_whitespace()):this.is_unformatted(g,B)?(h=this.get_unformatted("\x3c/"+g+"\x3e",b),f.push(h),this.pos-1,this.tag_type="SINGLE"):"script"===g&&(-1===b.search("type")||-1<b.search("type")&&-1<b.search(/\b(text|application)\/(x-)?(javascript|ecmascript|jscript|livescript)/))?a||(this.record_tag(g),this.tag_type="SCRIPT"):"style"===g&&(-1===b.search("type")||
+-1<b.search("type")&&-1<b.search("text/css"))?a||(this.record_tag(g),this.tag_type="STYLE"):"!"===g.charAt(0)?a||(this.tag_type="SINGLE",this.traverse_whitespace()):a||("/"===g.charAt(0)?(this.retrieve_tag(g.substring(1)),this.tag_type="END"):(this.record_tag(g),"html"!==g.toLowerCase()&&(this.indent_content=!0),this.tag_type="START"),this.traverse_whitespace()&&this.space_or_wrap(f),this.Utils.in_array(g,this.Utils.extra_liners)&&(this.print_newline(!1,this.output),this.output.length&&"\n"!==this.output[this.output.length-
+2]&&this.print_newline(!0,this.output))),a&&(this.pos=n,this.line_char_count=c),f.join("")},this.get_comment=function(a){var b="",d="\x3e",f=!1;this.pos=a;input_char=this.input.charAt(this.pos);for(this.pos++;this.pos<=this.input.length&&(b+=input_char,b.charAt(b.length-1)!==d.charAt(d.length-1)||-1===b.indexOf(d));)!f&&10>b.length&&(0===b.indexOf("\x3c![if")?(d="\x3c![endif]\x3e",f=!0):0===b.indexOf("\x3c![cdata[")?(d="]]\x3e",f=!0):0===b.indexOf("\x3c![")?(d="]\x3e",f=!0):0===b.indexOf("\x3c!--")?
+(d="--\x3e",f=!0):0===b.indexOf("{{!")?(d="}}",f=!0):0===b.indexOf("\x3c?")?(d="?\x3e",f=!0):0===b.indexOf("\x3c%")&&(d="%\x3e",f=!0)),input_char=this.input.charAt(this.pos),this.pos++;return b},this.get_unformatted=function(a,b){if(b&&-1!==b.toLowerCase().indexOf(a))return"";var d="",f="",l=0,h=!0;do{if(this.pos>=this.input.length)break;if(d=this.input.charAt(this.pos),this.pos++,this.Utils.in_array(d,this.Utils.whitespace)){if(!h){this.line_char_count--;continue}if("\n"===d||"\r"===d){f+="\n";this.line_char_count=
+0;continue}}f+=d;this.line_char_count++;h=!0;t&&"{"===d&&f.length&&"{"===f.charAt(f.length-2)&&(f+=this.get_unformatted("}}"),l=f.length)}while(-1===f.toLowerCase().indexOf(a,l));return f},this.get_token=function(){var a;if("TK_TAG_SCRIPT"===this.last_token||"TK_TAG_STYLE"===this.last_token){var b=this.last_token.substr(7);return a=this.get_contents_to(b),"string"!=typeof a?a:[a,"TK_"+b]}if("CONTENT"===this.current_mode)return a=this.get_content(),"string"!=typeof a?a:[a,"TK_CONTENT"];if("TAG"===
+this.current_mode)return"string"!=typeof(a=this.get_tag())?a:[a,"TK_TAG_"+this.tag_type]},this.get_full_indent=function(a){return a=this.indent_level+a||0,1>a?"":Array(a+1).join(this.indent_string)},this.is_unformatted=function(a,b){if(!this.Utils.in_array(a,b))return!1;if("a"!==a.toLowerCase()||!this.Utils.in_array("a",b))return!0;var d=(this.get_tag(!0)||"").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/);return!(d&&!this.Utils.in_array(d,b))},this.printer=function(a,b,d,f,l){this.input=a||"";this.input=
+this.input.replace(/\r\n|[\r\u2028\u2029]/g,"\n");this.output=[];this.indent_character=b;this.indent_string="";this.indent_size=d;this.brace_style=l;this.indent_level=0;this.wrap_line_length=f;for(a=this.line_char_count=0;a<this.indent_size;a++)this.indent_string+=this.indent_character;this.print_newline=function(a,b){this.line_char_count=0;b&&b.length&&(a||"\n"!==b[b.length-1])&&("\n"!==b[b.length-1]&&(b[b.length-1]=b[b.length-1].replace(/\s+$/g,"")),b.push("\n"))};this.print_indentation=function(a){for(var b=
+0;b<this.indent_level;b++)a.push(this.indent_string),this.line_char_count+=this.indent_string.length};this.print_token=function(a){this.is_whitespace(a)&&!this.output.length||((a||""!==a)&&this.output.length&&"\n"===this.output[this.output.length-1]&&(this.print_indentation(this.output),a=a.replace(/^\s+/g,"")),this.print_token_raw(a))};this.print_token_raw=function(a){0<this.newlines&&(a=a.replace(/\s+$/g,""));a&&""!==a&&(1<a.length&&"\n"===a.charAt(a.length-1)?(this.output.push(a.slice(0,-1)),this.print_newline(!1,
+this.output)):this.output.push(a));for(a=0;a<this.newlines;a++)this.print_newline(0<a,this.output);this.newlines=0};this.indent=function(){this.indent_level++};this.unindent=function(){0<this.indent_level&&this.indent_level--}},this};for(a.printer(f,l,r,w,p);;){f=a.get_token();if(a.token_text=f[0],a.token_type=f[1],"TK_EOF"===a.token_type)break;switch(a.token_type){case "TK_TAG_START":a.print_newline(!1,a.output);a.print_token(a.token_text);a.indent_content&&(a.indent(),a.indent_content=!1);a.current_mode=
+"CONTENT";break;case "TK_TAG_STYLE":case "TK_TAG_SCRIPT":a.print_newline(!1,a.output);a.print_token(a.token_text);a.current_mode="CONTENT";break;case "TK_TAG_END":"TK_CONTENT"===a.last_token&&""===a.last_text&&(f=a.token_text.match(/\w+/)[0],r=null,a.output.length&&(r=a.output[a.output.length-1].match(/(?:<|{{#)\s*(\w+)/)),(null===r||r[1]!==f&&!a.Utils.in_array(r[1],B))&&a.print_newline(!1,a.output));a.print_token(a.token_text);a.current_mode="CONTENT";break;case "TK_TAG_SINGLE":(f=a.token_text.match(/^\s*<([a-z-]+)/i))&&
+a.Utils.in_array(f[1],B)||a.print_newline(!1,a.output);a.print_token(a.token_text);a.current_mode="CONTENT";break;case "TK_TAG_HANDLEBARS_ELSE":a.print_token(a.token_text);a.indent_content&&(a.indent(),a.indent_content=!1);a.current_mode="CONTENT";break;case "TK_TAG_HANDLEBARS_COMMENT":case "TK_CONTENT":a.print_token(a.token_text);a.current_mode="TAG";break;case "TK_STYLE":case "TK_SCRIPT":if(""!==a.token_text){a.print_newline(!1,a.output);var u;f=a.token_text;w=1;"TK_SCRIPT"===a.token_type?u="function"==
+typeof x&&x:"TK_STYLE"===a.token_type&&(u="function"==typeof A&&A);"keep"===d.indent_scripts?w=0:"separate"===d.indent_scripts&&(w=-a.indent_level);r=a.get_full_indent(w);u?(w=function(){this.eol="\n"},w.prototype=d,w=new w,f=u(f.replace(/^\s*/,r),w)):(p=f.match(/^\s*/)[0].match(/[^\n\r]*$/)[0].split(a.indent_string).length-1,w=a.get_full_indent(w-p),f=f.replace(/^\s*/,r).replace(/\r\n|\r|\n/g,"\n"+w).replace(/\s+$/,""));f&&(a.print_token_raw(f),a.print_newline(!0,a.output))}a.current_mode="TAG";
+break;default:""!==a.token_text&&a.print_token(a.token_text)}a.last_token=a.token_type;a.last_text=a.token_text}d=a.output.join("").replace(/[\r\n\t ]+$/,"");return z&&(d+="\n"),"\n"!=b&&(d=d.replace(/[\n]/g,b)),d}if("function"==typeof define&&define.amd)define("beautify-html.js",["require","./beautify","./beautify-css"],function(x){var d=x("./beautify"),I=x("./beautify-css");return{html_beautify:function(x,a){return f(x,a,d.js_beautify,I.css_beautify)}}});else if("undefined"!=typeof exports){var x=
+require("./beautify.js"),I=require("./beautify-css.js");exports.html_beautify=function(K,d){return f(K,d,x.js_beautify,I.css_beautify)}}else"undefined"!=typeof window?window.html_beautify=function(x,d){return f(x,d,window.js_beautify,window.css_beautify)}:"undefined"!=typeof global&&(global.html_beautify=function(x,d){return f(x,d,global.js_beautify,global.css_beautify)})})();
+(function(f){"function"==typeof f.define&&(f.define("beautify",["beautify.js"],function(f){return f}),f.define("beautify-css",[],function(){return{css_beautify:void 0}}),f.define("beautifyModule",["beautify","beautify-html.js"],function(x,I){f.js_beautify=x.js_beautify;f.html_beautify=I.html_beautify}))})(this);
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/js/codemirror.addons.min.js b/js/ckeditor/plugins/codemirror/js/codemirror.addons.min.js
new file mode 100644 (file)
index 0000000..3fe1403
--- /dev/null
@@ -0,0 +1,103 @@
+!function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/comment/continuecomment.js",["../../lib/codemirror"],a):a(CodeMirror)}(function(a){function m(b){if(b.getOption("disableInput"))return a.Pass;for(var d,c=b.listSelections(),r=[],q=0;q<c.length;q++){var n=c[q].head,p=b.getTokenAt(n);if("comment"!=p.type)return a.Pass;var e=a.innerMode(b.getMode(),p.state).mode;if(d){if(d!=e)return a.Pass}else d=e;e=null;
+if(d.blockCommentStart&&d.blockCommentContinue){var l,f=p.string.indexOf(d.blockCommentEnd),k=b.getRange(a.Pos(n.line,0),a.Pos(n.line,p.end));if(!(-1!=f&&f==p.string.length-d.blockCommentEnd.length&&n.ch>=f))if(0==p.string.indexOf(d.blockCommentStart)){if(e=k.slice(0,p.start),!/^\s*$/.test(e))for(e="",f=0;f<p.start;++f)e+=" "}else-1!=(l=k.indexOf(d.blockCommentContinue))&&l+d.blockCommentContinue.length>p.start&&/^\s*$/.test(k.slice(0,l))&&(e=k.slice(0,l));null!=e&&(e+=d.blockCommentContinue)}null==
+e&&d.lineComment&&t(b)&&(n=b.getLine(n.line),l=n.indexOf(d.lineComment),-1<l&&(e=n.slice(0,l),/\S/.test(e)?e=null:e+=d.lineComment+n.slice(l+d.lineComment.length).match(/^\s*/)[0]));if(null==e)return a.Pass;r[q]="\n"+e}b.operation(function(){for(var f=c.length-1;0<=f;f--)b.replaceRange(r[f],c[f].from(),c[f].to(),"+insert")})}function t(b){b=b.getOption("continueComments");return!b||"object"!=typeof b||!1!==b.continueLineComment}for(var g=["clike","css","javascript"],c=0;c<g.length;++c)a.extendMode(g[c],
+{blockCommentContinue:" * "});a.defineOption("continueComments",null,function(b,d,c){if(c&&c!=a.Init&&b.removeKeyMap("continueComment"),d)c="Enter","string"==typeof d?c=d:"object"==typeof d&&d.key&&(c=d.key),d={name:"continueComment"},d[c]=m,b.addKeyMap(d)})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/edit/closebrackets.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function m(l,f){return"pairs"==f&&"string"==typeof l?l:"object"==typeof l&&null!=l[f]?l[f]:r[f]}function t(l){var f=l.state.closeBrackets;return!f||f.override?f:l.getModeAt(l.getCursor()).closeBrackets||f}function g(l,f){var k=t(l);if(!k||l.getOption("disableInput"))return a.Pass;
+var b=m(k,"pairs"),e=b.indexOf(f);if(-1==e)return a.Pass;for(var p,k=m(k,"triples"),n=b.charAt(e+1)==f,r=l.listSelections(),g=0==e%2,C=0;C<r.length;C++){var w;w=r[C];var u=w.head,y=l.getRange(u,q(u.line,u.ch+1));if(g&&!w.empty())w="surround";else if(!n&&g||y!=f)if(n&&1<u.ch&&0<=k.indexOf(f)&&l.getRange(q(u.line,u.ch-2),u)==f+f&&(2>=u.ch||l.getRange(q(u.line,u.ch-3),q(u.line,u.ch-2))!=f))w="addFour";else{if(n){if(a.isWordChar(y)||!d(l,u,f))return a.Pass}else if(!g||l.getLine(u.line).length!=u.ch&&
+!c(y,b)&&!/\s/.test(y))return a.Pass;w="both"}else w=n&&h(l,u)?"both":0<=k.indexOf(f)&&l.getRange(u,q(u.line,u.ch+3))==f+f+f?"skipThree":"skip";if(p){if(p!=w)return a.Pass}else p=w}var z=e%2?b.charAt(e-1):f,D=e%2?f:b.charAt(e+1);l.operation(function(){if("skip"==p)l.execCommand("goCharRight");else if("skipThree"==p)for(var f=0;3>f;f++)l.execCommand("goCharRight");else if("surround"==p){for(var k=l.getSelections(),f=0;f<k.length;f++)k[f]=z+k[f]+D;l.replaceSelections(k,"around");k=l.listSelections().slice();
+for(f=0;f<k.length;f++){var e=k,b=f,d;d=k[f];var c=0<a.cmpPos(d.anchor,d.head);d={anchor:new q(d.anchor.line,d.anchor.ch+(c?-1:1)),head:new q(d.head.line,d.head.ch+(c?1:-1))};e[b]=d}l.setSelections(k)}else"both"==p?(l.replaceSelection(z+D,null),l.triggerElectric(z+D),l.execCommand("goCharLeft")):"addFour"==p&&(l.replaceSelection(z+z+z+z,"before"),l.execCommand("goCharRight"))})}function c(l,f){var k=f.lastIndexOf(l);return-1<k&&1==k%2}function b(l,f){var k=l.getRange(q(f.line,f.ch-1),q(f.line,f.ch+
+1));return 2==k.length?k:null}function d(l,f,k){var e=l.getLine(f.line),b=l.getTokenAt(f);if(/\bstring2?\b/.test(b.type)||h(l,f))return!1;k=new a.StringStream(e.slice(0,f.ch)+k+e.slice(f.ch),4);for(k.pos=k.start=b.start;;){e=l.getMode().token(k,b.state);if(k.pos>=f.ch+1)return/\bstring2?\b/.test(e);k.start=k.pos}}function h(l,f){var k=l.getTokenAt(q(f.line,f.ch+1));return/\bstring/.test(k.type)&&k.start==f.ch}var r={pairs:"()[]{}''\"\"",triples:"",explode:"[]{}"},q=a.Pos;a.defineOption("autoCloseBrackets",
+!1,function(l,f,k){k&&k!=a.Init&&(l.removeKeyMap(p),l.state.closeBrackets=null);f&&(l.state.closeBrackets=f,l.addKeyMap(p))});for(var n=r.pairs+"`",p={Backspace:function(l){var f=t(l);if(!f||l.getOption("disableInput"))return a.Pass;for(var k=m(f,"pairs"),f=l.listSelections(),e=0;e<f.length;e++){if(!f[e].empty())return a.Pass;var d=b(l,f[e].head);if(!d||0!=k.indexOf(d)%2)return a.Pass}for(e=f.length-1;0<=e;e--)k=f[e].head,l.replaceRange("",q(k.line,k.ch-1),q(k.line,k.ch+1),"+delete")},Enter:function(e){var f=
+t(e),f=f&&m(f,"explode");if(!f||e.getOption("disableInput"))return a.Pass;for(var k=e.listSelections(),d=0;d<k.length;d++){if(!k[d].empty())return a.Pass;var c=b(e,k[d].head);if(!c||0!=f.indexOf(c)%2)return a.Pass}e.operation(function(){e.replaceSelection("\n\n",null);e.execCommand("goCharLeft");k=e.listSelections();for(var f=0;f<k.length;f++){var b=k[f].head.line;e.indentLine(b,null,!0);e.indentLine(b+1,null,!0)}})}},e=0;e<n.length;e++)p["'"+n.charAt(e)+"'"]=function(e){return function(f){return g(f,
+e)}}(n.charAt(e))});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/fold/xml-fold",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function m(e,b,f,k){this.line=b;this.ch=f;this.cm=e;this.text=e.getLine(b);this.min=k?Math.max(k.from,e.firstLine()):e.firstLine();this.max=k?Math.min(k.to-1,e.lastLine()):e.lastLine()}function t(e,b){var f=e.cm.getTokenTypeAt(n(e.line,b));return f&&/\btag\b/.test(f)}function g(e){if(!(e.line>=
+e.max))return e.ch=0,e.text=e.cm.getLine(++e.line),!0}function c(e){if(!(e.line<=e.min))return e.text=e.cm.getLine(--e.line),e.ch=e.text.length,!0}function b(e){for(;;){var b=e.text.indexOf("\x3e",e.ch);if(-1==b){if(g(e))continue;break}if(t(e,b+1)){var f=e.text.lastIndexOf("/",b),f=-1<f&&!/\S/.test(e.text.slice(f+1,b));return e.ch=b+1,f?"selfClose":"regular"}e.ch=b+1}}function d(e){for(;;){var b=e.ch?e.text.lastIndexOf("\x3c",e.ch-1):-1;if(-1==b){if(c(e))continue;break}if(t(e,b+1)){p.lastIndex=b;
+e.ch=b;var f=p.exec(e.text);if(f&&f.index==b)return f}else e.ch=b}}function h(e){for(;;){p.lastIndex=e.ch;var b=p.exec(e.text);if(!b){if(g(e))continue;break}if(t(e,b.index+1))return e.ch=b.index+b[0].length,b;e.ch=b.index+1}}function r(e,d){for(var f=[];;){var k,a=h(e),c=e.line,p=e.ch-(a?a[0].length:0);if(!a||!(k=b(e)))break;if("selfClose"!=k)if(a[1]){for(var q=f.length-1;0<=q;--q)if(f[q]==a[2]){f.length=q;break}if(0>q&&(!d||d==a[2]))return{tag:a[2],from:n(c,p),to:n(e.line,e.ch)}}else f.push(a[2])}}
+function q(b,a){for(var f=[];;){var k;a:for(k=b;;){var p=k.ch?k.text.lastIndexOf("\x3e",k.ch-1):-1;if(-1==p){if(c(k))continue;k=void 0;break a}if(t(k,p+1)){var h=k.text.lastIndexOf("/",p),h=-1<h&&!/\S/.test(k.text.slice(h+1,p));k=(k.ch=p+1,h?"selfClose":"regular");break a}k.ch=p}if(!k)break;if("selfClose"!=k){k=b.line;p=b.ch;h=d(b);if(!h)break;if(h[1])f.push(h[2]);else{for(var q=f.length-1;0<=q;--q)if(f[q]==h[2]){f.length=q;break}if(0>q&&(!a||a==h[2]))return{tag:h[2],from:n(b.line,b.ch),to:n(k,p)}}}else d(b)}}
+var n=a.Pos,p=RegExp("\x3c(/?)([A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD][A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD-:.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*)","g");a.registerHelper("fold","xml",function(e,a){for(var f=new m(e,a.line,0);;){var k,
+d=h(f);if(!d||f.line!=a.line||!(k=b(f)))break;if(!d[1]&&"selfClose"!=k)return k=n(f.line,f.ch),(f=r(f,d[2]))&&{from:k,to:f.from}}});a.findMatchingTag=function(e,a,f){var k=new m(e,a.line,a.ch,f);if(-1!=k.text.indexOf("\x3e")||-1!=k.text.indexOf("\x3c")){var c=b(k),p=c&&n(k.line,k.ch),h=c&&d(k);if(c&&h&&!(0<(k.line-a.line||k.ch-a.ch)))return a={from:n(k.line,k.ch),to:p,tag:h[2]},"selfClose"==c?{open:a,close:null,at:"open"}:h[1]?{open:q(k,h[2]),close:a,at:"close"}:(k=new m(e,p.line,p.ch,f),{open:a,
+close:r(k,h[2]),at:"open"})}};a.findEnclosingTag=function(b,a,f,k){for(var d=new m(b,a.line,a.ch,f);;){var c=q(d,k);if(!c)break;var p=new m(b,a.line,a.ch,f);if(p=r(p,c.tag))return{open:c,close:p}}};a.scanForClosingTag=function(b,a,f,k){return r(new m(b,a.line,a.ch,k?{from:0,to:k}:null),f)}});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("../fold/xml-fold")):"function"==typeof define&&define.amd?define("addon/edit/closetag.js",["../../lib/codemirror","../fold/xml-fold"],a):a(CodeMirror)})(function(a){function m(h){if(h.getOption("disableInput"))return a.Pass;for(var r=h.listSelections(),q=[],n=0;n<r.length;n++){if(!r[n].empty())return a.Pass;var p=r[n].head,e=h.getTokenAt(p),l=a.innerMode(h.getMode(),e.state),f=l.state;if("xml"!=
+l.mode.name||!f.tagName)return a.Pass;var k=h.getOption("autoCloseTags"),v="html"==l.mode.configuration,l="object"==typeof k&&k.dontCloseTags||v&&b,v="object"==typeof k&&k.indentTags||v&&d,k=f.tagName;e.end>p.ch&&(k=k.slice(0,k.length-e.end+p.ch));var t=k.toLowerCase();if(!k||"string"==e.type&&(e.end!=p.ch||!/[\"\']/.test(e.string.charAt(e.string.length-1))||1==e.string.length)||"tag"==e.type&&"closeTag"==f.type||e.string.indexOf("/")==e.string.length-1||l&&-1<g(l,t)||c(h,k,p,f,!0))return a.Pass;
+e=v&&-1<g(v,t);q[n]={indent:e,text:"\x3e"+(e?"\n\n":"")+"\x3c/"+k+"\x3e",newPos:e?a.Pos(p.line+1,0):a.Pos(p.line,p.ch+1)}}for(n=r.length-1;0<=n;n--)p=q[n],h.replaceRange(p.text,r[n].head,r[n].anchor,"+insert"),e=h.listSelections().slice(0),e[n]={head:p.newPos,anchor:p.newPos},h.setSelections(e),p.indent&&(h.indentLine(p.newPos.line,null,!0),h.indentLine(p.newPos.line+1,null,!0))}function t(b,d){for(var q=b.listSelections(),n=[],p=d?"/":"\x3c/",e=0;e<q.length;e++){if(!q[e].empty())return a.Pass;var l=
+q[e].head,f=b.getTokenAt(l),k=a.innerMode(b.getMode(),f.state),g=k.state;if(d&&("string"==f.type||"\x3c"!=f.string.charAt(0)||f.start!=l.ch-1))return a.Pass;if("xml"!=k.mode.name)if("htmlmixed"==b.getMode().name&&"javascript"==k.mode.name)k=p+"script";else{if("htmlmixed"!=b.getMode().name||"css"!=k.mode.name)return a.Pass;k=p+"style"}else{if(!g.context||!g.context.tagName||c(b,g.context.tagName,l,g))return a.Pass;k=p+g.context.tagName}"\x3e"!=b.getLine(l.line).charAt(f.end)&&(k+="\x3e");n[e]=k}b.replaceSelections(n);
+q=b.listSelections();for(e=0;e<q.length;e++)(e==q.length-1||q[e].head.line<q[e+1].head.line)&&b.indentLine(q[e].head.line)}function g(b,a){if(b.indexOf)return b.indexOf(a);for(var d=0,c=b.length;d<c;++d)if(b[d]==a)return d;return-1}function c(b,d,c,n,p){if(!a.scanForClosingTag)return!1;var e=Math.min(b.lastLine()+1,c.line+500);c=a.scanForClosingTag(b,c,null,e);if(!c||c.tag!=d)return!1;n=n.context;for(p=p?1:0;n&&n.tagName==d;n=n.prev)++p;c=c.to;for(n=1;n<p;n++){c=a.scanForClosingTag(b,c,null,e);if(!c||
+c.tag!=d)return!1;c=c.to}return!0}a.defineOption("autoCloseTags",!1,function(b,d,c){if(c!=a.Init&&c&&b.removeKeyMap("autoCloseTags"),d)c={name:"autoCloseTags"},("object"!=typeof d||d.whenClosing)&&(c["'/'"]=function(b){return b.getOption("disableInput")?a.Pass:t(b,!0)}),("object"!=typeof d||d.whenOpening)&&(c["'\x3e'"]=function(b){return m(b)}),b.addKeyMap(c)});var b="area base br col command embed hr img input keygen link meta param source track wbr".split(" "),d="applet blockquote body button div dl fieldset form frameset h1 h2 h3 h4 h5 h6 head html iframe layer legend object ol p select table ul".split(" ");
+a.commands.closeTag=function(b){return t(b)}});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/edit/matchbrackets.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function m(b,a,c){var e=b.getLineHandle(a.line),l=a.ch-1,f=c&&c.afterCursor;null==f&&(f=/(^| )cm-fat-cursor($| )/.test(b.getWrapperElement().className));e=!f&&0<=l&&h[e.text.charAt(l)]||h[e.text.charAt(++l)];if(!e)return null;f="\x3e"==e.charAt(1)?1:-1;if(c&&c.strict&&0<f!=
+(l==a.ch))return null;var k=b.getTokenTypeAt(d(a.line,l+1));b=t(b,d(a.line,l+(0<f?1:0)),f,k||null,c);return null==b?null:{from:d(a.line,l),to:b&&b.pos,match:b&&b.ch==e.charAt(0),forward:0<f}}function t(b,a,c,e,l){var f=l&&l.maxScanLineLength||1E4,k=l&&l.maxScanLines||1E3,g=[];l=l&&l.bracketRegex?l.bracketRegex:/[(){}[\]]/;for(var k=0<c?Math.min(a.line+k,b.lastLine()+1):Math.max(b.firstLine()-1,a.line-k),r=a.line;r!=k;r+=c){var t=b.getLine(r);if(t){var m=0<c?0:t.length-1,E=0<c?t.length:-1;if(!(t.length>
+f))for(r==a.line&&(m=a.ch-(0>c?1:0));m!=E;m+=c){var A=t.charAt(m);if(l.test(A)&&(void 0===e||b.getTokenTypeAt(d(r,m+1))==e))if("\x3e"==h[A].charAt(1)==0<c)g.push(A);else{if(!g.length)return{pos:d(r,m),ch:A};g.pop()}}}}return r-c!=(0<c?b.lastLine():b.firstLine())&&null}function g(a,c,p){for(var e=a.state.matchBrackets.maxHighlightLineLength||1E3,l=[],f=a.listSelections(),k=0;k<f.length;k++){var h=f[k].empty()&&m(a,f[k].head,p);if(h&&a.getLine(h.from.line).length<=e){var g=h.match?"CodeMirror-matchingbracket":
+"CodeMirror-nonmatchingbracket";l.push(a.markText(h.from,d(h.from.line,h.from.ch+1),{className:g}));h.to&&a.getLine(h.to.line).length<=e&&l.push(a.markText(h.to,d(h.to.line,h.to.ch+1),{className:g}))}}if(l.length){b&&a.state.focused&&a.focus();p=function(){a.operation(function(){for(var b=0;b<l.length;b++)l[b].clear()})};if(!c)return p;setTimeout(p,800)}}function c(b){b.operation(function(){r&&(r(),r=null);r=g(b,!1,b.state.matchBrackets)})}var b=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||
+8>document.documentMode),d=a.Pos,h={"(":")\x3e",")":"(\x3c","[":"]\x3e","]":"[\x3c","{":"}\x3e","}":"{\x3c"},r=null;a.defineOption("matchBrackets",!1,function(b,d,p){p&&p!=a.Init&&(b.off("cursorActivity",c),r&&(r(),r=null));d&&(b.state.matchBrackets="object"==typeof d?d:{},b.on("cursorActivity",c))});a.defineExtension("matchBrackets",function(){g(this,!0)});a.defineExtension("findMatchingBracket",function(b,a,c){return(c||"boolean"==typeof a)&&(c?(c.strict=a,a=c):a=a?{strict:!0}:null),m(this,b,a)});
+a.defineExtension("scanForBracket",function(b,a,c,e){return t(this,b,a,c,e)})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("../fold/xml-fold")):"function"==typeof define&&define.amd?define("addon/edit/matchtags.js",["../../lib/codemirror","../fold/xml-fold"],a):a(CodeMirror)})(function(a){function m(a){a.state.tagHit&&a.state.tagHit.clear();a.state.tagOther&&a.state.tagOther.clear();a.state.tagHit=a.state.tagOther=null}function t(c){c.state.failedTagMatch=!1;c.operation(function(){if(m(c),!c.somethingSelected()){var b=
+c.getCursor(),d=c.getViewport();d.from=Math.min(d.from,b.line);d.to=Math.max(b.line+1,d.to);if(b=a.findMatchingTag(c,b,d))c.state.matchBothTags&&(d="open"==b.at?b.open:b.close)&&(c.state.tagHit=c.markText(d.from,d.to,{className:"CodeMirror-matchingtag"})),(b="close"==b.at?b.open:b.close)?c.state.tagOther=c.markText(b.from,b.to,{className:"CodeMirror-matchingtag"}):c.state.failedTagMatch=!0}})}function g(a){a.state.failedTagMatch&&t(a)}a.defineOption("matchTags",!1,function(c,b,d){d&&d!=a.Init&&(c.off("cursorActivity",
+t),c.off("viewportChange",g),m(c));b&&(c.state.matchBothTags="object"==typeof b&&b.bothTags,c.on("cursorActivity",t),c.on("viewportChange",g),t(c))});a.commands.toMatchingTag=function(c){var b=a.findMatchingTag(c,c.getCursor());b&&(b="close"==b.at?b.open:b.close)&&c.extendSelection(b.to,b.from)}});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/edit/trailingspace.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){a.defineOption("showTrailingSpace",!1,function(m,t,g){g==a.Init&&(g=!1);g&&!t?m.removeOverlay("trailingspace"):!g&&t&&m.addOverlay({token:function(a){for(var b=a.string.length,d=b;d&&/\s/.test(a.string.charAt(d-1));--d);return d>a.pos?(a.pos=d,null):(a.pos=b,"trailingspace")},
+name:"trailingspace"})})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/fold/foldcode",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function m(b,d,c,r){function q(f){var a=n(b,d);if(!a||a.to.line-a.from.line<p)return null;for(var e=b.findMarksAt(a.from),c=0;c<e.length;++c)if(e[c].__isFold&&"fold"!==r){if(!f)return null;a.cleared=!0;e[c].clear()}return a}if(c&&c.call){var n=c;c=null}else n=g(b,c,"rangeFinder");
+"number"==typeof d&&(d=a.Pos(d,0));var p=g(b,c,"minFoldSize"),e=q(!0);if(g(b,c,"scanUp"))for(;!e&&d.line>b.firstLine();)d=a.Pos(d.line-1,0),e=q(!1);if(e&&!e.cleared&&"unfold"!==r){var l=t(b,c);a.on(l,"mousedown",function(b){f.clear();a.e_preventDefault(b)});var f=b.markText(e.from,e.to,{replacedWith:l,clearOnEnter:g(b,c,"clearOnEnter"),__isFold:!0});f.on("clear",function(f,c){a.signal(b,"unfold",b,f,c)});a.signal(b,"fold",b,e.from,e.to)}}function t(b,a){var c=g(b,a,"widget");if("string"==typeof c){var r=
+document.createTextNode(c),c=document.createElement("span");c.appendChild(r);c.className="CodeMirror-foldmarker"}else c&&(c=c.cloneNode(!0));return c}function g(b,a,h){return a&&void 0!==a[h]?a[h]:(b=b.options.foldOptions)&&void 0!==b[h]?b[h]:c[h]}a.newFoldFunction=function(b,a){return function(c,g){m(c,g,{rangeFinder:b,widget:a})}};a.defineExtension("foldCode",function(b,a,c){m(this,b,a,c)});a.defineExtension("isFolded",function(b){b=this.findMarksAt(b);for(var a=0;a<b.length;++a)if(b[a].__isFold)return!0});
+a.commands.toggleFold=function(b){b.foldCode(b.getCursor())};a.commands.fold=function(b){b.foldCode(b.getCursor(),null,"fold")};a.commands.unfold=function(b){b.foldCode(b.getCursor(),null,"unfold")};a.commands.foldAll=function(b){b.operation(function(){for(var c=b.firstLine(),h=b.lastLine();c<=h;c++)b.foldCode(a.Pos(c,0),null,"fold")})};a.commands.unfoldAll=function(b){b.operation(function(){for(var c=b.firstLine(),h=b.lastLine();c<=h;c++)b.foldCode(a.Pos(c,0),null,"unfold")})};a.registerHelper("fold",
+"combine",function(){var b=Array.prototype.slice.call(arguments,0);return function(a,c){for(var g=0;g<b.length;++g){var t=b[g](a,c);if(t)return t}}});a.registerHelper("fold","auto",function(b,a){for(var c=b.getHelpers(a,"fold"),g=0;g<c.length;g++){var t=c[g](b,a);if(t)return t}});var c={rangeFinder:a.fold.auto,widget:"↔",minFoldSize:0,scanUp:!1,clearOnEnter:!0};a.defineOption("foldOptions",null);a.defineExtension("foldOption",function(b,a){return g(this,b,a)})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("./foldcode")):"function"==typeof define&&define.amd?define("addon/fold/foldgutter.js",["../../lib/codemirror","./foldcode"],a):a(CodeMirror)})(function(a){function m(b){this.options=b;this.from=this.to=0}function t(b,a){for(var c=b.findMarks(n(a,0),n(a+1,0)),f=0;f<c.length;++f)if(c[f].__isFold&&c[f].find().from.line==a)return c[f]}function g(b){if("string"==typeof b){var a=document.createElement("div");
+return a.className=b+" CodeMirror-guttermarker-subtle",a}return b.cloneNode(!0)}function c(b,a,c){var f=b.state.foldGutter.options,k=a,d=b.foldOption(f,"minFoldSize"),h=b.foldOption(f,"rangeFinder");b.eachLine(a,c,function(a){var c=null;if(t(b,k))c=g(f.indicatorFolded);else{var e=n(k,0);(e=h&&h(b,e))&&e.to.line-e.from.line>=d&&(c=g(f.indicatorOpen))}b.setGutterMarker(a,f.gutter,c);++k})}function b(b){var a=b.getViewport(),d=b.state.foldGutter;d&&(b.operation(function(){c(b,a.from,a.to)}),d.from=a.from,
+d.to=a.to)}function d(b,a,c){var f=b.state.foldGutter;f&&(f=f.options,c==f.gutter&&((c=t(b,a))?c.clear():b.foldCode(n(a,0),f.rangeFinder)))}function h(a){var c=a.state.foldGutter;if(c){var d=c.options;c.from=c.to=0;clearTimeout(c.changeUpdate);c.changeUpdate=setTimeout(function(){b(a)},d.foldOnChangeTimeSpan||600)}}function r(a){var e=a.state.foldGutter;if(e){var d=e.options;clearTimeout(e.changeUpdate);e.changeUpdate=setTimeout(function(){var f=a.getViewport();e.from==e.to||20<f.from-e.to||20<e.from-
+f.to?b(a):a.operation(function(){f.from<e.from&&(c(a,f.from,e.from),e.from=f.from);f.to>e.to&&(c(a,e.to,f.to),e.to=f.to)})},d.updateViewportTimeSpan||400)}}function q(b,a){var d=b.state.foldGutter;if(d){var f=a.line;f>=d.from&&f<d.to&&c(b,f,f+1)}}a.defineOption("foldGutter",!1,function(c,e,l){l&&l!=a.Init&&(c.clearGutter(c.state.foldGutter.options.gutter),c.state.foldGutter=null,c.off("gutterClick",d),c.off("change",h),c.off("viewportChange",r),c.off("fold",q),c.off("unfold",q),c.off("swapDoc",h));
+if(e){l=c.state;var f=e;e=(!0===f&&(f={}),null==f.gutter&&(f.gutter="CodeMirror-foldgutter"),null==f.indicatorOpen&&(f.indicatorOpen="CodeMirror-foldgutter-open"),null==f.indicatorFolded&&(f.indicatorFolded="CodeMirror-foldgutter-folded"),f);l.foldGutter=new m(e);b(c);c.on("gutterClick",d);c.on("change",h);c.on("viewportChange",r);c.on("fold",q);c.on("unfold",q);c.on("swapDoc",h)}});var n=a.Pos});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/fold/brace-fold.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){a.registerHelper("fold","brace",function(m,t){function g(f){for(var k=t.ch,e=0;;)if(k=0>=k?-1:d.lastIndexOf(f,k-1),-1!=k){if(1==e&&k<t.ch)break;if(c=m.getTokenTypeAt(a.Pos(b,k+1)),!/^(comment|string)/.test(c))return k+1;--k}else{if(1==e)break;e=1;k=d.length}}var c,b=t.line,d=
+m.getLine(b),h="{",r="}",q=g("{");if(null==q&&(h="[",r="]",q=g("[")),null!=q){var n,p,e=1,l=m.lastLine(),f=b;a:for(;f<=l;++f)for(var k=m.getLine(f),v=f==b?q:0;;){var x=k.indexOf(h,v),B=k.indexOf(r,v);if(0>x&&(x=k.length),0>B&&(B=k.length),(v=Math.min(x,B))==k.length)break;if(m.getTokenTypeAt(a.Pos(f,v+1))==c)if(v==x)++e;else if(!--e){n=f;p=v;break a}++v}if(null!=n&&(b!=n||p!=q))return{from:a.Pos(b,q),to:a.Pos(n,p)}}});a.registerHelper("fold","import",function(m,t){function g(b){if(b<m.firstLine()||
+b>m.lastLine())return null;var c=m.getTokenAt(a.Pos(b,1));if(/\S/.test(c.string)||(c=m.getTokenAt(a.Pos(b,c.end+1))),"keyword"!=c.type||"import"!=c.string)return null;var d=b;for(b=Math.min(m.lastLine(),b+10);d<=b;++d){var g=m.getLine(d).indexOf(";");if(-1!=g)return{startCh:c.end,end:a.Pos(d,g)}}}var c,b=t.line,d=g(b);if(!d||g(b-1)||(c=g(b-2))&&c.end.line==b-1)return null;for(c=d.end;;){var h=g(c.line+1);if(null==h)break;c=h.end}return{from:m.clipPos(a.Pos(b,d.startCh+1)),to:c}});a.registerHelper("fold",
+"include",function(m,t){function g(b){if(b<m.firstLine()||b>m.lastLine())return null;var c=m.getTokenAt(a.Pos(b,1));return/\S/.test(c.string)||(c=m.getTokenAt(a.Pos(b,c.end+1))),"meta"==c.type&&"#include"==c.string.slice(0,8)?c.start+8:void 0}var c=t.line,b=g(c);if(null==b||null!=g(c-1))return null;for(var d=c;null!=g(d+1);)++d;return{from:a.Pos(c,b+1),to:m.clipPos(a.Pos(d))}})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/fold/comment-fold.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){a.registerGlobalHelper("fold","comment",function(a){return a.blockCommentStart&&a.blockCommentEnd},function(m,t){var g=m.getModeAt(t),c=g.blockCommentStart,g=g.blockCommentEnd;if(c&&g){var b,d=t.line;b=m.getLine(d);for(var h=t.ch,r=0;;)if(h=0>=h?-1:b.lastIndexOf(c,h-1),-1!=
+h){if(1==r&&h<t.ch)return;if(/comment/.test(m.getTokenTypeAt(a.Pos(d,h+1)))&&(0==h||b.slice(h-g.length,h)==g||!/comment/.test(m.getTokenTypeAt(a.Pos(d,h))))){b=h+c.length;break}--h}else{if(1==r)return;r=1;h=b.length}var q,n,r=1,h=m.lastLine(),p=d;a:for(;p<=h;++p)for(var e=m.getLine(p),l=p==d?b:0;;){var f=e.indexOf(c,l),k=e.indexOf(g,l);if(0>f&&(f=e.length),0>k&&(k=e.length),(l=Math.min(f,k))==e.length)break;if(l==f)++r;else if(!--r){q=p;n=l;break a}++l}if(null!=q&&(d!=q||n!=b))return{from:a.Pos(d,
+b),to:a.Pos(q,n)}}})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/fold/indent-fold.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function m(t,g){var c=t.getLine(g),b=c.search(/\S/);return-1==b||/\bcomment\b/.test(t.getTokenTypeAt(a.Pos(g,b+1)))?-1:a.countColumn(c,null,t.getOption("tabSize"))}a.registerHelper("fold","indent",function(t,g){var c=m(t,g.line);if(!(0>c)){for(var b=null,d=g.line+1,h=t.lastLine();d<=
+h;++d){var r=m(t,d);if(-1!=r){if(!(r>c))break;b=d}}return b?{from:a.Pos(g.line,t.getLine(g.line).length),to:a.Pos(b,t.getLine(b).length)}:void 0}})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/format/autoFormatAll.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){a.defineExtension("autoFormatAll",function(m,t){for(var g=this,c=g.getMode(),b=g.getRange(m,t).split("\n"),d=a.copyState(c,g.getTokenAt(m).state),h=g.getOption("tabSize"),r="",q=0,n=0==m.ch,p=0;p<b.length;++p){for(var e=new a.StringStream(b[p],h);!e.eol();){var l=a.innerMode(c,
+d),f=c.token(e,d),k=e.current();e.start=e.pos;n&&!/\S/.test(k)||(r+=k,n=!1);!n&&l.mode.newlineAfterToken&&l.mode.newlineAfterToken(f,k,e.string.slice(e.pos)||b[p+1]||"",l.state)&&(r+="\n",n=!0,++q)}!e.pos&&c.blankLine&&c.blankLine(d);!n&&p<b.length-1&&(r+="\n",n=!0,++q)}g.operation(function(){g.replaceRange(r,m,t);for(var b=m.line+1,a=m.line+q;b<=a;++b)g.indentLine(b,"smart");g.setCursor({line:0,ch:0})})})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/format/formatting.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function m(a){for(var g=[/for\s*?\((.*?)\)/g,/&#?[a-z0-9]+;[\s\S]/g,/\"(.*?)((\")|$)/g,/\/\*(.*?)(\*\/|$)/g,/^\/\/.*/g],c=[],b=0;b<g.length;b++)for(var d=0;d<a.length;){var h=a.substr(d).match(g[b]);if(null==h)break;c.push({start:d+h.index,end:d+h.index+h[0].length});d+=h.index+
+Math.max(1,h[0].length)}return c.sort(function(b,a){return b.start-a.start}),c}a.extendMode("css",{commentStart:"/*",commentEnd:"*/",newlineAfterToken:function(a,g){return/^[;{}]$/.test(g)}});a.extendMode("javascript",{commentStart:"/*",commentEnd:"*/",wordWrapChars:[";","\\{","\\}"],autoFormatLineBreaks:function(a){var g=0,c=this.jsonMode?function(b){return b.replace(/([,{])/g,"$1\n").replace(/}/g,"\n}")}:function(b){return b.replace(/(;|\{|\})([^\r\n;])/g,"$1\n$2")},b=m(a),d="";if(null!=b){for(var h=
+0;h<b.length;h++)b[h].start>g&&(d+=c(a.substring(g,b[h].start)),g=b[h].start),b[h].start<=g&&b[h].end>=g&&(d+=a.substring(g,b[h].end),g=b[h].end);g<a.length&&(d+=c(a.substr(g)))}else d=c(a);return d.replace(/^\n*|\n*$/,"")}});a.extendMode("xml",{commentStart:"\x3c!--",commentEnd:"--\x3e",noBreak:!1,noBreakEmpty:null,tagType:"",tagName:"",isXML:!1,newlineAfterToken:function(a,g,c,b){b=!1;var d=null,h="";if(this.isXML="xml"==this.configuration,"comment"==a||/\x3c!--/.test(c))return!1;if("tag"==a){0==
+g.indexOf("\x3c")&&0==!g.indexOf("\x3c/")&&(this.tagType="open",d=g.match(/^<\s*?([\w]+?)$/i),this.tagName=null!=d?d[1]:"",h=this.tagName.toLowerCase(),-1!="|label|li|option|textarea|title|a|b|bdi|bdo|big|center|cite|del|em|font|i|img|ins|s|small|span|strike|strong|sub|sup|u|".indexOf("|"+h+"|")&&(this.noBreak=!0));if(0==g.indexOf("\x3e")&&"open"==this.tagType)return this.tagType="",RegExp("^"+(this.isXML?"[^\x3c]*?":"")+"\x3c/s*?"+this.tagName+"s*?\x3e","i").test(c)?(this.noBreak=!1,this.isXML||
+(this.tagName=""),!1):(b=this.noBreak,this.noBreak=!1,!b);if(0==g.indexOf("\x3c/")&&(this.tagType="close",d=g.match(/^<\/\s*?([\w]+?)$/i),null!=d&&(h=d[1].toLowerCase()),-1!="|a|b|bdi|bdo|big|center|cite|del|em|font|i|img|ins|s|small|span|strike|strong|sub|sup|u|".indexOf("|"+h+"|")&&(this.noBreak=!0)),0==g.indexOf("\x3e")&&"close"==this.tagType)return this.tagType="",0==c.indexOf("\x3c")&&(d=c.match(/^<\/?\s*?([\w]+?)(\s|>)/i),h=null!=d?d[1].toLowerCase():"",-1=="|label|li|option|textarea|title|a|b|bdi|bdo|big|center|cite|del|em|font|i|img|ins|s|small|span|strike|strong|sub|sup|u|".indexOf("|"+
+h+"|"))?(this.noBreak=!1,!0):(b=this.noBreak,this.noBreak=!1,!b)}return 0==c.indexOf("\x3c")&&(this.noBreak=!1,this.isXML&&""!=this.tagName?(this.tagName="",!1):(d=c.match(/^<\/?\s*?([\w]+?)(\s|>)/i),h=null!=d?d[1].toLowerCase():"",-1=="|label|li|option|textarea|title|a|b|bdi|bdo|big|center|cite|del|em|font|i|img|ins|s|small|span|strike|strong|sub|sup|u|".indexOf("|"+h+"|")))}});a.defineExtension("commentRange",function(t,g,c){var b=this,d=a.innerMode(b.getMode(),b.getTokenAt(g).state).mode;b.operation(function(){if(t)b.replaceRange(d.commentEnd,
+c),b.replaceRange(d.commentStart,g),b.setSelection(g,{line:c.line,ch:c.ch+d.commentStart.length+d.commentEnd.length}),g.line==c.line&&g.ch==c.ch&&b.setCursor(g.line,g.ch+d.commentStart.length);else{var a=b.getRange(g,c),r=a.indexOf(d.commentStart),q=a.lastIndexOf(d.commentEnd);-1<r&&-1<q&&q>r&&(a=a.substr(0,r)+a.substring(r+d.commentStart.length,q)+a.substr(q+d.commentEnd.length));b.replaceRange(a,g,c);b.setSelection(g,{line:c.line,ch:c.ch-d.commentStart.length-d.commentEnd.length})}})});a.defineExtension("autoIndentRange",
+function(a,g){var c=this;this.operation(function(){for(var b=a.line;b<=g.line;b++)c.indentLine(b,"smart")})});a.defineExtension("autoFormatRange",function(t,g){for(var c=this,b=c.getMode(),d=c.getRange(t,g).split("\n"),h=a.copyState(b,c.getTokenAt(t).state),r=c.getOption("tabSize"),q="",n=0,p=0==t.ch,e=0;e<d.length;++e){for(var l=new a.StringStream(d[e],r);!l.eol();){var f=a.innerMode(b,h),k=b.token(l,h),m=l.current();l.start=l.pos;p&&!/\S/.test(m)||(q+=m,p=!1);!p&&f.mode.newlineAfterToken&&f.mode.newlineAfterToken(k,
+m,l.string.slice(l.pos)||d[e+1]||"",f.state)&&(q+="\n",p=!0,++n)}!l.pos&&b.blankLine&&b.blankLine(h);!p&&e<d.length-1&&(q+="\n",p=!0,++n)}c.operation(function(){c.replaceRange(q,t,g);for(var b=t.line+1,a=t.line+n;b<=a;++b)c.indentLine(b,"smart");c.setSelection(t,c.getCursor(!1))})})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/selection/active-line.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function m(a){for(var c=0;c<a.state.activeLines.length;c++)a.removeLineClass(a.state.activeLines[c],"wrap",b),a.removeLineClass(a.state.activeLines[c],"background",d),a.removeLineClass(a.state.activeLines[c],"gutter",h)}function t(b,a){if(b.length!=a.length)return!1;for(var c=
+0;c<b.length;c++)if(b[c]!=a[c])return!1;return!0}function g(a,c){for(var g=[],p=0;p<c.length;p++){var e=c[p],l=a.getOption("styleActiveLine");if("object"==typeof l&&l.nonEmpty?e.anchor.line==e.head.line:e.empty())e=a.getLineHandleVisualStart(e.head.line),g[g.length-1]!=e&&g.push(e)}t(a.state.activeLines,g)||a.operation(function(){m(a);for(var c=0;c<g.length;c++)a.addLineClass(g[c],"wrap",b),a.addLineClass(g[c],"background",d),a.addLineClass(g[c],"gutter",h);a.state.activeLines=g})}function c(b,a){g(b,
+a.ranges)}var b="CodeMirror-activeline",d="CodeMirror-activeline-background",h="CodeMirror-activeline-gutter";a.defineOption("styleActiveLine",!1,function(b,d,h){h=h!=a.Init&&h;d!=h&&(h&&(b.off("beforeSelectionChange",c),m(b),delete b.state.activeLines),d&&(b.state.activeLines=[],g(b,b.listSelections()),b.on("beforeSelectionChange",c)))})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/search/searchcursor",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function m(b){if(!b.global){var a=b.flags;b=new RegExp(b.source,(null!=a?a:(b.ignoreCase?"i":"")+(b.global?"g":"")+(b.multiline?"m":""))+"g")}return b}function t(b,a,c){a=m(a);var e=c.line,d=c.ch;for(c=b.lastLine();e<=c;e++,d=0)if(a.lastIndex=d,d=b.getLine(e),d=a.exec(d))return{from:l(e,
+d.index),to:l(e,d.index+d[0].length),match:d}}function g(b,a,c){if(!/\\s|\\n|\n|\\W|\\D|\[\^/.test(a.source))return t(b,a,c);a=m(a);for(var d,e=1,g=c.line,h=b.lastLine();g<=h;){for(var p=0;p<e;p++){var n=b.getLine(g++);d=null==d?n:d+"\n"+n}e*=2;a.lastIndex=c.ch;if(p=a.exec(d))return a=d.slice(0,p.index).split("\n"),b=p[0].split("\n"),c=c.line+a.length-1,a=a[a.length-1].length,{from:l(c,a),to:l(c+b.length-1,1==b.length?a+b[0].length:b[b.length-1].length),match:p}}}function c(b,a){for(var c,d=0;;){a.lastIndex=
+d;var e=a.exec(b);if(!e||(c=e,(d=c.index+(c[0].length||1))==b.length))return c}}function b(b,a,d){a=m(a);var e=d.line,g=d.ch;for(d=b.firstLine();e>=d;e--,g=-1){var h=b.getLine(e);-1<g&&(h=h.slice(0,g));if(g=c(h,a))return{from:l(e,g.index),to:l(e,g.index+g[0].length),match:g}}}function d(b,a,d){a=m(a);for(var e,g=1,h=d.line,p=b.firstLine();h>=p;){for(var n=0;n<g;n++){var t=b.getLine(h--);e=null==e?t.slice(0,d.ch):t+"\n"+e}g*=2;if(n=c(e,a))return a=e.slice(0,n.index).split("\n"),b=n[0].split("\n"),
+h+=a.length,a=a[a.length-1].length,{from:l(h,a),to:l(h+b.length-1,1==b.length?a+b[0].length:b[b.length-1].length),match:n}}}function h(b,a,c,d){if(b.length==a.length)return c;var e=0;for(a=c+Math.max(0,b.length-a.length);;){if(e==a)return e;var g=e+a>>1,l=d(b.slice(0,g)).length;if(l==c)return g;l>c?a=g:e=g+1}}function r(b,a,c,d){if(!a.length)return null;d=d?p:e;a=d(a).split(/\r|\n\r?/);var g=c.line;c=c.ch;var n=b.lastLine()+1-a.length;a:for(;g<=n;g++,c=0){var t=b.getLine(g).slice(c),m=d(t);if(1==
+a.length){var q=m.indexOf(a[0]);if(-1==q)continue a;h(t,m,q,d);return{from:l(g,h(t,m,q,d)+c),to:l(g,h(t,m,q+a[0].length,d)+c)}}q=m.length-a[0].length;if(m.slice(q)==a[0]){for(var r=1;r<a.length-1;r++)if(d(b.getLine(g+r))!=a[r])continue a;var r=b.getLine(g+a.length-1),u=d(r),y=a[a.length-1];if(r.slice(0,y.length)==y)return{from:l(g,h(t,m,q,d)+c),to:l(g+a.length-1,h(r,u,y.length,d))}}}}function q(a,b,c,d){if(!b.length)return null;d=d?p:e;b=d(b).split(/\r|\n\r?/);var g=c.line,n=c.ch,t=a.firstLine()-
+1+b.length;a:for(;g>=t;g--,n=-1){var m=a.getLine(g);-1<n&&(m=m.slice(0,n));n=d(m);if(1==b.length){c=n.lastIndexOf(b[0]);if(-1==c)continue a;return{from:l(g,h(m,n,c,d)),to:l(g,h(m,n,c+b[0].length,d))}}var q=b[b.length-1];if(n.slice(0,q.length)==q){var r=1;for(c=g-b.length+1;r<b.length-1;r++)if(d(a.getLine(c+r))!=b[r])continue a;c=a.getLine(g+1-b.length);r=d(c);if(r.slice(r.length-b[0].length)==b[0])return{from:l(g+1-b.length,h(c,r,c.length-b[0].length,d)),to:l(g,h(m,n,q.length,d))}}}}function n(a,
+c,e,h){this.atOccurrence=!1;this.doc=a;e=e?a.clipPos(e):l(0,0);this.pos={from:e,to:e};var n;"object"==typeof h?n=h.caseFold:(n=h,h=null);"string"==typeof c?(null==n&&(n=!1),this.matches=function(b,d){return(b?q:r)(a,c,d,n)}):(c=m(c),h&&!1===h.multiline?this.matches=function(d,e){return(d?b:t)(a,c,e)}:this.matches=function(b,e){return(b?d:g)(a,c,e)})}var p,e,l=a.Pos;String.prototype.normalize?(p=function(b){return b.normalize("NFD").toLowerCase()},e=function(b){return b.normalize("NFD")}):(p=function(b){return b.toLowerCase()},
+e=function(b){return b});n.prototype={findNext:function(){return this.find(!1)},findPrevious:function(){return this.find(!0)},find:function(b){for(var c=this.matches(b,this.doc.clipPos(b?this.pos.from:this.pos.to));c&&0==a.cmpPos(c.from,c.to);)b?c.from.ch?c.from=l(c.from.line,c.from.ch-1):c=c.from.line==this.doc.firstLine()?null:this.matches(b,this.doc.clipPos(l(c.from.line-1))):c.to.ch<this.doc.getLine(c.to.line).length?c.to=l(c.to.line,c.to.ch+1):c=c.to.line==this.doc.lastLine()?null:this.matches(b,
+l(c.to.line+1,0));if(c)return this.pos=c,this.atOccurrence=!0,this.pos.match||!0;b=l(b?this.doc.firstLine():this.doc.lastLine()+1,0);return this.pos={from:b,to:b},this.atOccurrence=!1},from:function(){if(this.atOccurrence)return this.pos.from},to:function(){if(this.atOccurrence)return this.pos.to},replace:function(b,c){if(this.atOccurrence){var d=a.splitLines(b);this.doc.replaceRange(d,this.pos.from,this.pos.to,c);this.pos.to=l(this.pos.from.line+d.length-1,d[d.length-1].length+(1==d.length?this.pos.from.ch:
+0))}}};a.defineExtension("getSearchCursor",function(b,a,c){return new n(this.doc,b,a,c)});a.defineDocExtension("getSearchCursor",function(b,a,c){return new n(this,b,a,c)});a.defineExtension("selectMatches",function(b,c){for(var d=[],e=this.getSearchCursor(b,this.getCursor("from"),c);e.findNext()&&!(0<a.cmpPos(e.to(),this.getCursor("to")));)d.push({anchor:e.from(),head:e.to()});d.length&&this.setSelections(d,0)})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/scroll/annotatescrollbar",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function m(a,g){function c(a){clearTimeout(b.doRedraw);b.doRedraw=setTimeout(function(){b.redraw()},a)}this.cm=a;this.options=g;this.buttonHeight=g.scrollButtonHeight||a.getOption("scrollButtonHeight");this.annotations=[];this.doRedraw=this.doUpdate=null;this.div=a.getWrapperElement().appendChild(document.createElement("div"));
+this.div.style.cssText="position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none";this.computeScale();var b=this;a.on("refresh",this.resizeHandler=function(){clearTimeout(b.doUpdate);b.doUpdate=setTimeout(function(){b.computeScale()&&c(20)},100)});a.on("markerAdded",this.resizeHandler);a.on("markerCleared",this.resizeHandler);!1!==g.listenForChanges&&a.on("change",this.changeHandler=function(){c(250)})}a.defineExtension("annotateScrollbar",function(a){return"string"==typeof a&&(a={className:a}),
+new m(this,a)});a.defineOption("scrollButtonHeight",0);m.prototype.computeScale=function(){var a=this.cm,a=(a.getWrapperElement().clientHeight-a.display.barHeight-2*this.buttonHeight)/a.getScrollerElement().scrollHeight;if(a!=this.hScale)return this.hScale=a,!0};m.prototype.update=function(a){this.annotations=a;this.redraw()};m.prototype.redraw=function(a){function g(a,b){return q!=a.line&&(q=a.line,n=c.getLineHandle(q)),n.widgets&&n.widgets.length||h&&n.height>m?c.charCoords(a,"local")[b?"top":"bottom"]:
+c.heightAtLine(n,"local")+(b?0:n.height)}!1!==a&&this.computeScale();var c=this.cm;a=this.hScale;var b=document.createDocumentFragment(),d=this.annotations,h=c.getOption("lineWrapping"),m=h&&1.5*c.defaultTextHeight(),q=null,n=null,p=c.lastLine();if(c.display.barWidth)for(var e,l=0;l<d.length;l++){var f=d[l];if(!(f.to.line>p)){for(var k=e||g(f.from,!0)*a,v=g(f.to,!1)*a;l<d.length-1&&!(d[l+1].to.line>p)&&!((e=g(d[l+1].from,!0)*a)>v+.9);)f=d[++l],v=g(f.to,!1)*a;if(v!=k){var v=Math.max(v-k,3),x=b.appendChild(document.createElement("div"));
+x.style.cssText="position: absolute; right: 0px; width: "+Math.max(c.display.barWidth-1,2)+"px; top: "+(k+this.buttonHeight)+"px; height: "+v+"px";x.className=this.options.className;f.id&&x.setAttribute("annotation-id",f.id)}}}this.div.textContent="";this.div.appendChild(b)};m.prototype.clear=function(){this.cm.off("refresh",this.resizeHandler);this.cm.off("markerAdded",this.resizeHandler);this.cm.off("markerCleared",this.resizeHandler);this.changeHandler&&this.cm.off("change",this.changeHandler);
+this.div.parentNode.removeChild(this.div)}});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("./searchcursor"),require("../scroll/annotatescrollbar")):"function"==typeof define&&define.amd?define("addon/search/matchesonscrollbar",["../../lib/codemirror","./searchcursor","../scroll/annotatescrollbar"],a):a(CodeMirror)})(function(a){function m(a,c,b,d){this.cm=a;this.options=d;var h={listenForChanges:!1},m;for(m in d)h[m]=d[m];h.className||(h.className="CodeMirror-search-match");this.annotation=
+a.annotateScrollbar(h);this.query=c;this.caseFold=b;this.gap={from:a.firstLine(),to:a.lastLine()+1};this.matches=[];this.update=null;this.findMatches();this.annotation.update(this.matches);var q=this;a.on("change",this.changeHandler=function(a,b){q.onChange(b)})}function t(a,c,b){return a<=c?a:Math.max(c,a+b)}a.defineExtension("showMatchesOnScrollbar",function(a,c,b){return"string"==typeof b&&(b={className:b}),b||(b={}),new m(this,a,c,b)});m.prototype.findMatches=function(){if(this.gap){for(var g=
+0;g<this.matches.length;g++){var c=this.matches[g];if(c.from.line>=this.gap.to)break;c.to.line>=this.gap.from&&this.matches.splice(g--,1)}for(var b=this.cm.getSearchCursor(this.query,a.Pos(this.gap.from,0),this.caseFold),d=this.options&&this.options.maxMatches||1E3;b.findNext();){c={from:b.from(),to:b.to()};if(c.from.line>=this.gap.to)break;if(this.matches.splice(g++,0,c),this.matches.length>d)break}this.gap=null}};m.prototype.onChange=function(g){var c=g.from.line,b=a.changeEnd(g).line,d=b-g.to.line;
+if(this.gap?(this.gap.from=Math.min(t(this.gap.from,c,d),g.from.line),this.gap.to=Math.max(t(this.gap.to,c,d),g.from.line)):this.gap={from:g.from.line,to:b+1},d)for(g=0;g<this.matches.length;g++){var b=this.matches[g],h=t(b.from.line,c,d);h!=b.from.line&&(b.from=a.Pos(h,b.from.ch));h=t(b.to.line,c,d);h!=b.to.line&&(b.to=a.Pos(h,b.to.ch))}clearTimeout(this.update);var m=this;this.update=setTimeout(function(){m.updateAfterChange()},250)};m.prototype.updateAfterChange=function(){this.findMatches();this.annotation.update(this.matches)};
+m.prototype.clear=function(){this.cm.off("change",this.changeHandler);this.annotation.clear()}});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("./matchesonscrollbar")):"function"==typeof define&&define.amd?define("addon/search/match-highlighter.js",["../../lib/codemirror","./matchesonscrollbar"],a):a(CodeMirror)})(function(a){function m(a){this.options={};for(var b in q)this.options[b]=(a&&a.hasOwnProperty(b)?a:q)[b];this.matchesonscroll=this.overlay=this.timeout=null;this.active=!1}function t(a){var b=a.state.matchHighlighter;(b.active||
+a.hasFocus())&&c(a,b)}function g(a){var b=a.state.matchHighlighter;b.active||(b.active=!0,c(a,b))}function c(a,b){clearTimeout(b.timeout);b.timeout=setTimeout(function(){h(a)},b.options.delay)}function b(a,b,c,d){var f=a.state.matchHighlighter;if(a.addOverlay(f.overlay=r(b,c,d)),f.options.annotateScrollbar&&a.showMatchesOnScrollbar)f.matchesonscroll=a.showMatchesOnScrollbar(c?new RegExp("\\b"+b+"\\b"):b,!1,{className:"CodeMirror-selection-highlight-scrollbar"})}function d(a){var b=a.state.matchHighlighter;
+b.overlay&&(a.removeOverlay(b.overlay),b.overlay=null,b.matchesonscroll&&(b.matchesonscroll.clear(),b.matchesonscroll=null))}function h(a){a.operation(function(){var c=a.state.matchHighlighter;if(d(a),!a.somethingSelected()&&c.options.showToken){for(var e=!0===c.options.showToken?/[\w$]/:c.options.showToken,g=a.getCursor(),f=a.getLine(g.line),h=g=g.ch;g&&e.test(f.charAt(g-1));)--g;for(;h<f.length&&e.test(f.charAt(h));)++h;return void(g<h&&b(a,f.slice(g,h),e,c.options.style))}e=a.getCursor("from");
+f=a.getCursor("to");if((g=e.line==f.line)&&!(g=!c.options.wordsOnly))a:if(null!==a.getRange(e,f).match(/^\w+$/)){if(0<e.ch&&(g={line:e.line,ch:e.ch-1},g=a.getRange(g,e),null===g.match(/\W/))){g=!1;break a}if(f.ch<a.getLine(e.line).length&&(g={line:f.line,ch:f.ch+1},g=a.getRange(f,g),null===g.match(/\W/))){g=!1;break a}g=!0}else g=!1;g&&(e=a.getRange(e,f),c.options.trim&&(e=e.replace(/^\s+|\s+$/g,"")),e.length>=c.options.minChars&&b(a,e,!1,c.options.style))})}function r(a,b,c){return{token:function(d){var f;
+if(f=d.match(a))(f=!b)||(f=!(d.start&&b.test(d.string.charAt(d.start-1))||d.pos!=d.string.length&&b.test(d.string.charAt(d.pos))));if(f)return c;d.next();d.skipTo(a.charAt(0))||d.skipToEnd()}}}var q={style:"matchhighlight",minChars:2,delay:100,wordsOnly:!1,annotateScrollbar:!1,showToken:!1,trim:!0};a.defineOption("highlightSelectionMatches",!1,function(b,c,e){if(e&&e!=a.Init&&(d(b),clearTimeout(b.state.matchHighlighter.timeout),b.state.matchHighlighter=null,b.off("cursorActivity",t),b.off("focus",
+g)),c)c=b.state.matchHighlighter=new m(c),b.hasFocus()?(c.active=!0,h(b)):b.on("focus",g),b.on("cursorActivity",t)})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/mode/multiplex.js",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){a.multiplexingMode=function(m){function t(a,b,d,g){return"string"==typeof b?(d=a.indexOf(b,d),g&&-1<d?d+b.length:d):(b=b.exec(d?a.slice(d):a))?b.index+d+(g?b[0].length:0):-1}var g=Array.prototype.slice.call(arguments,1);return{startState:function(){return{outer:a.startState(m),
+innerActive:null,inner:null}},copyState:function(c){return{outer:a.copyState(m,c.outer),innerActive:c.innerActive,inner:c.innerActive&&a.copyState(c.innerActive.mode,c.inner)}},token:function(c,b){if(b.innerActive){var d=b.innerActive,h=c.string;if(!d.close&&c.sol())return b.innerActive=b.inner=null,this.token(c,b);var r=d.close?t(h,d.close,c.pos,d.parseDelimiters):-1;if(r==c.pos&&!d.parseDelimiters)return c.match(d.close),b.innerActive=b.inner=null,d.delimStyle&&d.delimStyle+" "+d.delimStyle+"-close";
+-1<r&&(c.string=h.slice(0,r));var q=d.mode.token(c,b.inner);return-1<r&&(c.string=h),r==c.pos&&d.parseDelimiters&&(b.innerActive=b.inner=null),d.innerStyle&&(q=q?q+" "+d.innerStyle:d.innerStyle),q}d=1/0;h=c.string;for(q=0;q<g.length;++q){var n=g[q],r=t(h,n.open,c.pos);if(r==c.pos)return n.parseDelimiters||c.match(n.open),b.innerActive=n,b.inner=a.startState(n.mode,m.indent?m.indent(b.outer,""):0),n.delimStyle&&n.delimStyle+" "+n.delimStyle+"-open";-1!=r&&r<d&&(d=r)}d!=1/0&&(c.string=h.slice(0,d));
+r=m.token(c,b.outer);return d!=1/0&&(c.string=h),r},indent:function(c,b){var d=c.innerActive?c.innerActive.mode:m;return d.indent?d.indent(c.innerActive?c.inner:c.outer,b):a.Pass},blankLine:function(c){var b=c.innerActive?c.innerActive.mode:m;if(b.blankLine&&b.blankLine(c.innerActive?c.inner:c.outer),c.innerActive)"\n"===c.innerActive.close&&(c.innerActive=c.inner=null);else for(var d=0;d<g.length;++d){var h=g[d];"\n"===h.open&&(c.innerActive=h,c.inner=a.startState(h.mode,b.indent?b.indent(c.outer,
+""):0))}},electricChars:m.electricChars,innerMode:function(a){return a.inner?{state:a.inner,mode:a.innerActive.mode}:{state:a.outer,mode:m}}}}});
+(function(a){"function"==typeof a.define&&a.define("addons","addon/comment/continuecomment.js addon/edit/closebrackets.js addon/edit/closetag.js addon/edit/matchbrackets.js addon/edit/matchtags.js addon/edit/trailingspace.js addon/fold/foldgutter.js addon/fold/brace-fold.js addon/fold/comment-fold.js addon/fold/indent-fold.js addon/format/autoFormatAll.js addon/format/formatting.js addon/selection/active-line.js addon/search/match-highlighter.js addon/mode/multiplex.js".split(" "),function(){})})(this);
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/js/codemirror.addons.search.min.js b/js/ckeditor/plugins/codemirror/js/codemirror.addons.search.min.js
new file mode 100644 (file)
index 0000000..5f906a0
--- /dev/null
@@ -0,0 +1,26 @@
+!function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/search/searchcursor",["../../lib/codemirror"],a):a(CodeMirror)}(function(a){function x(d){if(!d.global){var b=d.flags;d=new RegExp(d.source,(null!=b?b:(d.ignoreCase?"i":"")+(d.global?"g":"")+(d.multiline?"m":""))+"g")}return d}function z(d,b,e){b=x(b);var k=e.line,f=e.ch;for(e=d.lastLine();k<=e;k++,f=0)if(b.lastIndex=f,f=d.getLine(k),f=b.exec(f))return{from:m(k,
+f.index),to:m(k,f.index+f[0].length),match:f}}function q(d,b,e){if(!/\\s|\\n|\n|\\W|\\D|\[\^/.test(b.source))return z(d,b,e);b=x(b);for(var k,f=1,a=e.line,c=d.lastLine();a<=c;){for(var h=0;h<f;h++){var t=d.getLine(a++);k=null==k?t:k+"\n"+t}f*=2;b.lastIndex=e.ch;if(h=b.exec(k))return b=k.slice(0,h.index).split("\n"),d=h[0].split("\n"),e=e.line+b.length-1,b=b[b.length-1].length,{from:m(e,b),to:m(e+d.length-1,1==d.length?b+d[0].length:d[d.length-1].length),match:h}}}function p(d,b){for(var e,k=0;;){b.lastIndex=
+k;var f=b.exec(d);if(!f||(e=f,(k=e.index+(e[0].length||1))==d.length))return e}}function c(d,b,e){b=x(b);var k=e.line,f=e.ch;for(e=d.firstLine();k>=e;k--,f=-1){var a=d.getLine(k);-1<f&&(a=a.slice(0,f));if(f=p(a,b))return{from:m(k,f.index),to:m(k,f.index+f[0].length),match:f}}}function g(d,b,e){b=x(b);for(var k,a=1,c=e.line,n=d.firstLine();c>=n;){for(var h=0;h<a;h++){var t=d.getLine(c--);k=null==k?t.slice(0,e.ch):t+"\n"+k}a*=2;if(h=p(k,b))return b=k.slice(0,h.index).split("\n"),d=h[0].split("\n"),
+c+=b.length,b=b[b.length-1].length,{from:m(c,b),to:m(c+d.length-1,1==d.length?b+d[0].length:d[d.length-1].length),match:h}}}function l(d,b,e,a){if(d.length==b.length)return e;var f=0;for(b=e+Math.max(0,d.length-b.length);;){if(f==b)return f;var c=f+b>>1,m=a(d.slice(0,c)).length;if(m==e)return c;m>e?b=c:f=c+1}}function r(d,b,e,a){if(!b.length)return null;a=a?n:y;b=a(b).split(/\r|\n\r?/);var f=e.line;e=e.ch;var c=d.lastLine()+1-b.length;a:for(;f<=c;f++,e=0){var g=d.getLine(f).slice(e),h=a(g);if(1==
+b.length){var t=h.indexOf(b[0]);if(-1==t)continue a;l(g,h,t,a);return{from:m(f,l(g,h,t,a)+e),to:m(f,l(g,h,t+b[0].length,a)+e)}}t=h.length-b[0].length;if(h.slice(t)==b[0]){for(var u=1;u<b.length-1;u++)if(a(d.getLine(f+u))!=b[u])continue a;var u=d.getLine(f+b.length-1),E=a(u),A=b[b.length-1];if(u.slice(0,A.length)==A)return{from:m(f,l(g,h,t,a)+e),to:m(f+b.length-1,l(u,E,A.length,a))}}}}function v(d,b,a,c){if(!b.length)return null;c=c?n:y;b=c(b).split(/\r|\n\r?/);var f=a.line,g=a.ch,q=d.firstLine()-
+1+b.length;a:for(;f>=q;f--,g=-1){var h=d.getLine(f);-1<g&&(h=h.slice(0,g));g=c(h);if(1==b.length){a=g.lastIndexOf(b[0]);if(-1==a)continue a;return{from:m(f,l(h,g,a,c)),to:m(f,l(h,g,a+b[0].length,c))}}var t=b[b.length-1];if(g.slice(0,t.length)==t){var u=1;for(a=f-b.length+1;u<b.length-1;u++)if(c(d.getLine(a+u))!=b[u])continue a;a=d.getLine(f+1-b.length);u=c(a);if(u.slice(u.length-b[0].length)==b[0])return{from:m(f+1-b.length,l(a,u,a.length-b[0].length,c)),to:m(f,l(h,g,t.length,c))}}}}function w(a,
+b,e,k){this.atOccurrence=!1;this.doc=a;e=e?a.clipPos(e):m(0,0);this.pos={from:e,to:e};var f;"object"==typeof k?f=k.caseFold:(f=k,k=null);"string"==typeof b?(null==f&&(f=!1),this.matches=function(c,e){return(c?v:r)(a,b,e,f)}):(b=x(b),k&&!1===k.multiline?this.matches=function(e,f){return(e?c:z)(a,b,f)}:this.matches=function(c,e){return(c?g:q)(a,b,e)})}var n,y,m=a.Pos;String.prototype.normalize?(n=function(a){return a.normalize("NFD").toLowerCase()},y=function(a){return a.normalize("NFD")}):(n=function(a){return a.toLowerCase()},
+y=function(a){return a});w.prototype={findNext:function(){return this.find(!1)},findPrevious:function(){return this.find(!0)},find:function(d){for(var b=this.matches(d,this.doc.clipPos(d?this.pos.from:this.pos.to));b&&0==a.cmpPos(b.from,b.to);)d?b.from.ch?b.from=m(b.from.line,b.from.ch-1):b=b.from.line==this.doc.firstLine()?null:this.matches(d,this.doc.clipPos(m(b.from.line-1))):b.to.ch<this.doc.getLine(b.to.line).length?b.to=m(b.to.line,b.to.ch+1):b=b.to.line==this.doc.lastLine()?null:this.matches(d,
+m(b.to.line+1,0));if(b)return this.pos=b,this.atOccurrence=!0,this.pos.match||!0;d=m(d?this.doc.firstLine():this.doc.lastLine()+1,0);return this.pos={from:d,to:d},this.atOccurrence=!1},from:function(){if(this.atOccurrence)return this.pos.from},to:function(){if(this.atOccurrence)return this.pos.to},replace:function(d,b){if(this.atOccurrence){var c=a.splitLines(d);this.doc.replaceRange(c,this.pos.from,this.pos.to,b);this.pos.to=m(this.pos.from.line+c.length-1,c[c.length-1].length+(1==c.length?this.pos.from.ch:
+0))}}};a.defineExtension("getSearchCursor",function(a,b,c){return new w(this.doc,a,b,c)});a.defineDocExtension("getSearchCursor",function(a,b,c){return new w(this,a,b,c)});a.defineExtension("selectMatches",function(c,b){for(var e=[],k=this.getSearchCursor(c,this.getCursor("from"),b);k.findNext()&&!(0<a.cmpPos(k.to(),this.getCursor("to")));)e.push({anchor:k.from(),head:k.to()});e.length&&this.setSelections(e,0)})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/dialog/dialog",["../../lib/codemirror"],a):a(CodeMirror)})(function(a){function x(a,p,c){var g;return g=a.getWrapperElement().appendChild(document.createElement("div")),g.className=c?"CodeMirror-dialog CodeMirror-dialog-bottom":"CodeMirror-dialog CodeMirror-dialog-top","string"==typeof p?g.innerHTML=p:g.appendChild(p),g}function z(a,p){a.state.currentNotificationClose&&
+a.state.currentNotificationClose();a.state.currentNotificationClose=p}a.defineExtension("openDialog",function(q,p,c){function g(a){"string"==typeof a?n.value=a:v||(v=!0,r.parentNode.removeChild(r),w.focus(),c.onClose&&c.onClose(r))}c||(c={});z(this,null);var l,r=x(this,q,c.bottom),v=!1,w=this,n=r.getElementsByTagName("input")[0];return n?(n.focus(),c.value&&(n.value=c.value,!1!==c.selectValueOnOpen&&n.select()),c.onInput&&a.on(n,"input",function(a){c.onInput(a,n.value,g)}),c.onKeyUp&&a.on(n,"keyup",
+function(a){c.onKeyUp(a,n.value,g)}),a.on(n,"keydown",function(l){c&&c.onKeyDown&&c.onKeyDown(l,n.value,g)||((27==l.keyCode||!1!==c.closeOnEnter&&13==l.keyCode)&&(n.blur(),a.e_stop(l),g()),13==l.keyCode&&p(n.value,l))}),!1!==c.closeOnBlur&&a.on(n,"blur",g)):(l=r.getElementsByTagName("button")[0])&&(a.on(l,"click",function(){g();w.focus()}),!1!==c.closeOnBlur&&a.on(l,"blur",g),l.focus()),g});a.defineExtension("openConfirm",function(q,p,c){function g(){r||(r=!0,l.parentNode.removeChild(l),v.focus())}
+z(this,null);var l=x(this,q,c&&c.bottom);q=l.getElementsByTagName("button");var r=!1,v=this,w=1;q[0].focus();for(c=0;c<q.length;++c){var n=q[c];!function(c){a.on(n,"click",function(l){a.e_preventDefault(l);g();c&&c(v)})}(p[c]);a.on(n,"blur",function(){--w;setTimeout(function(){0>=w&&g()},200)});a.on(n,"focus",function(){++w})}});a.defineExtension("openNotification",function(q,p){function c(){r||(r=!0,clearTimeout(g),l.parentNode.removeChild(l))}z(this,c);var g,l=x(this,q,p&&p.bottom),r=!1,v=p&&void 0!==
+p.duration?p.duration:5E3;return a.on(l,"click",function(g){a.e_preventDefault(g);c()}),v&&(g=setTimeout(c,v)),c})});
+(function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror"),require("./searchcursor"),require("../dialog/dialog")):"function"==typeof define&&define.amd?define("addon/search/search.js",["../../lib/codemirror","./searchcursor","../dialog/dialog"],a):a(CodeMirror)})(function(a){function x(h,a){return"string"==typeof h?h=new RegExp(h.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$\x26"),a?"gi":"g"):h.global||(h=new RegExp(h.source,h.ignoreCase?"gi":"g")),{token:function(a){h.lastIndex=
+a.pos;var b=h.exec(a.string);if(b&&b.index==a.pos)return a.pos+=b[0].length||1,"searching";b?a.pos=b.index:a.skipToEnd()}}}function z(){this.overlay=this.posFrom=this.posTo=this.lastQuery=this.query=null}function q(h){return h.state.search||(h.state.search=new z)}function p(h){return"string"==typeof h&&h==h.toLowerCase()}function c(h,a,b){return h.getSearchCursor(a,b,{caseFold:p(a),multiline:!0})}function g(h,a,b,c,f){h.openDialog(a,c,{value:b,selectValueOnOpen:!0,closeOnEnter:!1,onClose:function(){d(h)},
+onKeyDown:f})}function l(h,a,b,c,d){h.openDialog?h.openDialog(a,d,{value:c,selectValueOnOpen:!0}):d(prompt(b,c))}function r(a,b,c,d){a.openConfirm?a.openConfirm(b,d):confirm(c)&&d[0]()}function v(a){return a.replace(/\\(.)/g,function(a,h){return"n"==h?"\n":"r"==h?"\r":h})}function w(a){var b=a.match(/^\/(.*)\/([a-z]*)$/);if(b)try{a=new RegExp(b[1],-1==b[2].indexOf("i")?"":"i")}catch(c){}else a=v(a);return("string"==typeof a?""==a:a.test(""))&&(a=/x^/),a}function n(a,b,c){b.queryText=c;b.query=w(c);
+a.removeOverlay(b.overlay,p(b.query));b.overlay=x(b.query,p(b.query));a.addOverlay(b.overlay);a.showMatchesOnScrollbar&&(b.annotate&&(b.annotate.clear(),b.annotate=null),b.annotate=a.showMatchesOnScrollbar(b.query,p(b.query)))}function y(b,c,d,f){var e=q(b);if(e.query)return m(b,c);var p=b.getSelection()||e.lastQuery;if(d&&b.openDialog){var B=null,r=function(c,d){a.e_stop(d);c&&(c!=e.queryText&&(n(b,e,c),e.posFrom=e.posTo=b.getCursor()),B&&(B.style.opacity=1),m(b,d.shiftKey,function(a,c){var d;3>
+c.line&&document.querySelector&&(d=b.display.wrapper.querySelector(".CodeMirror-dialog"))&&d.getBoundingClientRect().bottom-4>b.cursorCoords(c,"window").top&&((B=d).style.opacity=.4)}))};g(b,k,p,r,function(c,d){var e=a.keyName(c),f=a.keyMap[b.getOption("keyMap")][e];f||(f=b.getOption("extraKeys")[e]);"findNext"==f||"findPrev"==f||"findPersistentNext"==f||"findPersistentPrev"==f?(a.e_stop(c),n(b,q(b),d),b.execCommand(f)):"find"!=f&&"findPersistent"!=f||(a.e_stop(c),r(d,c))});f&&p&&(n(b,e,p),m(b,c))}else l(b,
+k,"Search for:",p,function(a){a&&!e.query&&b.operation(function(){n(b,e,a);e.posFrom=e.posTo=b.getCursor();m(b,c)})})}function m(b,d,f){b.operation(function(){var e=q(b),g=c(b,e.query,d?e.posFrom:e.posTo);(g.find(d)||(g=c(b,e.query,d?a.Pos(b.lastLine()):a.Pos(b.firstLine(),0)),g.find(d)))&&(b.setSelection(g.from(),g.to()),b.scrollIntoView({from:g.from(),to:g.to()},20),e.posFrom=g.from(),e.posTo=g.to(),f&&f(g.from(),g.to()))})}function d(b){b.operation(function(){var a=q(b);(a.lastQuery=a.query)&&
+(a.query=a.queryText=null,b.removeOverlay(a.overlay),a.annotate&&(a.annotate.clear(),a.annotate=null))})}function b(b,a,d){b.operation(function(){for(var e=c(b,a);e.findNext();)if("string"!=typeof a){var f=b.getRange(e.from(),e.to()).match(a);e.replace(d.replace(/\$(\d)/g,function(b,a){return f[a]}))}else e.replace(d)})}function e(a,e){if(!a.getOption("readOnly")){var g=a.getSelection()||q(a).lastQuery,k='\x3cspan class\x3d"CodeMirror-search-label"\x3e'+(e?"Replace all:":"Replace:")+"\x3c/span\x3e";
+l(a,k+f,k,g,function(f){f&&(f=w(f),l(a,C,"Replace with:","",function(g){if(g=v(g),e)b(a,f,g);else{d(a);var k=c(a,f,a.getCursor("from")),l=function(){var d,e=k.from();!(d=k.findNext())&&(k=c(a,f),!(d=k.findNext())||e&&k.from().line==e.line&&k.from().ch==e.ch)||(a.setSelection(k.from(),k.to()),a.scrollIntoView({from:k.from(),to:k.to()}),r(a,D,"Replace?",[function(){m(d)},l,function(){b(a,f,g)}]))},m=function(a){k.replace("string"==typeof f?g:g.replace(/\$(\d)/g,function(b,c){return a[c]}));l()};l()}}))})}}
+var k='\x3cspan class\x3d"CodeMirror-search-label"\x3eSearch:\x3c/span\x3e \x3cinput type\x3d"text" style\x3d"width: 10em" class\x3d"CodeMirror-search-field"/\x3e \x3cspan style\x3d"color: #888" class\x3d"CodeMirror-search-hint"\x3e(Use /re/ syntax for regexp search)\x3c/span\x3e',f=' \x3cinput type\x3d"text" style\x3d"width: 10em" class\x3d"CodeMirror-search-field"/\x3e \x3cspan style\x3d"color: #888" class\x3d"CodeMirror-search-hint"\x3e(Use /re/ syntax for regexp search)\x3c/span\x3e',C='\x3cspan class\x3d"CodeMirror-search-label"\x3eWith:\x3c/span\x3e \x3cinput type\x3d"text" style\x3d"width: 10em" class\x3d"CodeMirror-search-field"/\x3e',
+D='\x3cspan class\x3d"CodeMirror-search-label"\x3eReplace?\x3c/span\x3e \x3cbutton\x3eYes\x3c/button\x3e \x3cbutton\x3eNo\x3c/button\x3e \x3cbutton\x3eAll\x3c/button\x3e \x3cbutton\x3eStop\x3c/button\x3e';a.commands.find=function(a){d(a);y(a)};a.commands.findPersistent=function(a){d(a);y(a,!1,!0)};a.commands.findPersistentNext=function(a){y(a,!1,!0,!0)};a.commands.findPersistentPrev=function(a){y(a,!0,!0,!0)};a.commands.findNext=y;a.commands.findPrev=function(a){y(a,!0)};a.commands.clearSearch=d;
+a.commands.replace=e;a.commands.replaceAll=function(a){e(a,!0)}});(function(a){"function"==typeof a.define&&a.define("addonSearch",["addon/search/search.js"],function(){})})(this);
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/js/codemirror.min.js b/js/ckeditor/plugins/codemirror/js/codemirror.min.js
new file mode 100644 (file)
index 0000000..2f07d97
--- /dev/null
@@ -0,0 +1,315 @@
+!function(ga,X){"object"==typeof exports&&"undefined"!=typeof module?module.exports=X():"function"==typeof define&&define.amd?define("codemirror.js",X):ga.CodeMirror=X()}(this,function(){function ga(a){return new RegExp("(^|\\s)"+a+"(?:$|\\s)\\s*")}function X(a){for(var b=a.childNodes.length;0<b;--b)a.removeChild(a.firstChild);return a}function Z(a,b){return X(a).appendChild(b)}function r(a,b,c,d){a=document.createElement(a);if(c&&(a.className=c),d&&(a.style.cssText=d),"string"==typeof b)a.appendChild(document.createTextNode(b));
+else if(b)for(c=0;c<b.length;++c)a.appendChild(b[c]);return a}function Za(a,b,c,d){a=r(a,b,c,d);return a.setAttribute("role","presentation"),a}function va(a,b){if(3==b.nodeType&&(b=b.parentNode),a.contains)return a.contains(b);do if(11==b.nodeType&&(b=b.host),b==a)return!0;while(b=b.parentNode)}function qa(){var a;try{a=document.activeElement}catch(b){a=document.body||null}for(;a&&a.shadowRoot&&a.shadowRoot.activeElement;)a=a.shadowRoot.activeElement;return a}function Ea(a,b){var c=a.className;ga(b).test(c)||
+(a.className+=(c?" ":"")+b)}function Jc(a,b){for(var c=a.split(" "),d=0;d<c.length;d++)c[d]&&!ga(c[d]).test(b)&&(b+=" "+c[d]);return b}function Kc(a){var b=Array.prototype.slice.call(arguments,1);return function(){return a.apply(null,b)}}function Fa(a,b,c){b||(b={});for(var d in a)!a.hasOwnProperty(d)||!1===c&&b.hasOwnProperty(d)||(b[d]=a[d]);return b}function ea(a,b,c,d,e){null==b&&-1==(b=a.search(/[^\s\u00a0]/))&&(b=a.length);d=d||0;for(e=e||0;;){var f=a.indexOf("\t",d);if(0>f||f>=b)return e+(b-
+d);e+=f-d;e+=c-e%c;d=f+1}}function N(a,b){for(var c=0;c<a.length;++c)if(a[c]==b)return c;return-1}function Lc(a,b,c){for(var d=0,e=0;;){var f=a.indexOf("\t",d);-1==f&&(f=a.length);var g=f-d;if(f==a.length||e+g>=b)return d+Math.min(g,b-e);if(e+=f-d,e+=c-e%c,d=f+1,e>=b)return d}}function Mc(a){for(;dc.length<=a;)dc.push(z(dc)+" ");return dc[a]}function z(a){return a[a.length-1]}function ec(a,b){for(var c=[],d=0;d<a.length;d++)c[d]=b(a[d],d);return c}function bg(a,b,c){for(var d=0,e=c(b);d<a.length&&
+c(a[d])<=e;)d++;a.splice(d,0,b)}function Qd(){}function Rd(a,b){var c;return Object.create?c=Object.create(a):(Qd.prototype=a,c=new Qd),b&&Fa(b,c),c}function Nc(a){return/\w/.test(a)||"\80"<a&&(a.toUpperCase()!=a.toLowerCase()||cg.test(a))}function fc(a,b){return b?!!(-1<b.source.indexOf("\\w")&&Nc(a))||b.test(a):Nc(a)}function Sd(a){for(var b in a)if(a.hasOwnProperty(b)&&a[b])return!1;return!0}function Oc(a){return 768<=a.charCodeAt(0)&&dg.test(a)}function Td(a,b,c){for(;(0>c?0<b:b<a.length)&&Oc(a.charAt(b));)b+=
+c;return b}function gc(a,b,c){for(;;){if(1>=Math.abs(b-c))return a(b)?b:c;var d=Math.floor((b+c)/2);a(d)?c=d:b=d}}function eg(a,b,c){this.input=c;this.scrollbarFiller=r("div",null,"CodeMirror-scrollbar-filler");this.scrollbarFiller.setAttribute("cm-not-content","true");this.gutterFiller=r("div",null,"CodeMirror-gutter-filler");this.gutterFiller.setAttribute("cm-not-content","true");this.lineDiv=Za("div",null,"CodeMirror-code");this.selectionDiv=r("div",null,null,"position: relative; z-index: 1");
+this.cursorDiv=r("div",null,"CodeMirror-cursors");this.measure=r("div",null,"CodeMirror-measure");this.lineMeasure=r("div",null,"CodeMirror-measure");this.lineSpace=Za("div",[this.measure,this.lineMeasure,this.selectionDiv,this.cursorDiv,this.lineDiv],null,"position: relative; outline: none");var d=Za("div",[this.lineSpace],"CodeMirror-lines");this.mover=r("div",[d],null,"position: relative");this.sizer=r("div",[this.mover],"CodeMirror-sizer");this.sizerWidth=null;this.heightForcer=r("div",null,null,
+"position: absolute; height: "+Ud+"px; width: 1px;");this.gutters=r("div",null,"CodeMirror-gutters");this.lineGutter=null;this.scroller=r("div",[this.sizer,this.heightForcer,this.gutters],"CodeMirror-scroll");this.scroller.setAttribute("tabIndex","-1");this.wrapper=r("div",[this.scrollbarFiller,this.gutterFiller,this.scroller],"CodeMirror");C&&8>B&&(this.gutters.style.zIndex=-1,this.scroller.style.paddingRight=0);R||wa&&rb||(this.scroller.draggable=!0);a&&(a.appendChild?a.appendChild(this.wrapper):
+a(this.wrapper));this.reportedViewFrom=this.reportedViewTo=this.viewFrom=this.viewTo=b.first;this.view=[];this.externalMeasured=this.renderedView=null;this.lastWrapHeight=this.lastWrapWidth=this.viewOffset=0;this.updateLineNumbers=null;this.nativeBarWidth=this.barHeight=this.barWidth=0;this.scrollbarsClipped=!1;this.lineNumWidth=this.lineNumInnerWidth=this.lineNumChars=null;this.alignWidgets=!1;this.maxLine=this.cachedCharWidth=this.cachedTextHeight=this.cachedPaddingH=null;this.maxLineLength=0;this.maxLineChanged=
+!1;this.wheelDX=this.wheelDY=this.wheelStartX=this.wheelStartY=null;this.shift=!1;this.activeTouch=this.selForContextMenu=null;c.init(this)}function w(a,b){if(0>(b-=a.first)||b>=a.size)throw Error("There is no line "+(b+a.first)+" in the document.");for(var c=a;!c.lines;)for(var d=0;;++d){var e=c.children[d],f=e.chunkSize();if(b<f){c=e;break}b-=f}return c.lines[b]}function Ga(a,b,c){var d=[],e=b.line;return a.iter(b.line,c.line+1,function(a){a=a.text;e==c.line&&(a=a.slice(0,c.ch));e==b.line&&(a=a.slice(b.ch));
+d.push(a);++e}),d}function Pc(a,b,c){var d=[];return a.iter(b,c,function(a){d.push(a.text)}),d}function la(a,b){var c=b-a.height;if(c)for(var d=a;d;d=d.parent)d.height+=c}function D(a){if(null==a.parent)return null;var b=a.parent;a=N(b.lines,a);for(var c=b.parent;c;b=c,c=c.parent)for(var d=0;c.children[d]!=b;++d)a+=c.children[d].chunkSize();return a+b.first}function Ha(a,b){var c=a.first;a:do{for(var d=0;d<a.children.length;++d){var e=a.children[d],f=e.height;if(b<f){a=e;continue a}b-=f;c+=e.chunkSize()}return c}while(!a.lines);
+for(d=0;d<a.lines.length;++d){e=a.lines[d].height;if(b<e)break;b-=e}return c+d}function sb(a,b){return b>=a.first&&b<a.first+a.size}function Qc(a,b){return String(a.lineNumberFormatter(b+a.firstLineNumber))}function m(a,b,c){if(void 0===c&&(c=null),!(this instanceof m))return new m(a,b,c);this.line=a;this.ch=b;this.sticky=c}function x(a,b){return a.line-b.line||a.ch-b.ch}function Rc(a,b){return a.sticky==b.sticky&&0==x(a,b)}function Sc(a){return m(a.line,a.ch)}function hc(a,b){return 0>x(a,b)?b:a}
+function ic(a,b){return 0>x(a,b)?a:b}function v(a,b){if(b.line<a.first)return m(a.first,0);var c=a.first+a.size-1;if(b.line>c)c=m(c,w(a,c).text.length);else var c=w(a,b.line).text.length,d=b.ch,c=null==d||d>c?m(b.line,c):0>d?m(b.line,0):b;return c}function Vd(a,b){for(var c=[],d=0;d<b.length;d++)c[d]=v(a,b[d]);return c}function jc(a,b,c){this.marker=a;this.from=b;this.to=c}function tb(a,b){if(a)for(var c=0;c<a.length;++c){var d=a[c];if(d.marker==b)return d}}function Tc(a,b){if(b.full)return null;
+var c=sb(a,b.from.line)&&w(a,b.from.line).markedSpans,d=sb(a,b.to.line)&&w(a,b.to.line).markedSpans;if(!c&&!d)return null;var e=b.from.ch,f=b.to.ch,g=0==x(b.from,b.to),h;if(c)for(var k=0;k<c.length;++k){var l=c[k],n=l.marker;if(null==l.from||(n.inclusiveLeft?l.from<=e:l.from<e)||!(l.from!=e||"bookmark"!=n.type||g&&l.marker.insertLeft)){var q=null==l.to||(n.inclusiveRight?l.to>=e:l.to>e);(h||(h=[])).push(new jc(n,l.from,q?null:l.to))}}var c=h,p;if(d)for(h=0;h<d.length;++h)if(k=d[h],l=k.marker,null==
+k.to||(l.inclusiveRight?k.to>=f:k.to>f)||k.from==f&&"bookmark"==l.type&&(!g||k.marker.insertLeft))n=null==k.from||(l.inclusiveLeft?k.from<=f:k.from<f),(p||(p=[])).push(new jc(l,n?null:k.from-f,null==k.to?null:k.to-f));d=p;f=1==b.text.length;g=z(b.text).length+(f?e:0);if(c)for(p=0;p<c.length;++p)h=c[p],null==h.to&&((k=tb(d,h.marker))?f&&(h.to=null==k.to?null:k.to+g):h.to=e);if(d)for(e=0;e<d.length;++e)p=d[e],(null!=p.to&&(p.to+=g),null==p.from)?tb(c,p.marker)||(p.from=g,f&&(c||(c=[])).push(p)):(p.from+=
+g,f&&(c||(c=[])).push(p));c&&(c=Wd(c));d&&d!=c&&(d=Wd(d));e=[c];if(!f){var u,f=b.text.length-2;if(0<f&&c)for(g=0;g<c.length;++g)null==c[g].to&&(u||(u=[])).push(new jc(c[g].marker,null,null));for(c=0;c<f;++c)e.push(u);e.push(d)}return e}function Wd(a){for(var b=0;b<a.length;++b){var c=a[b];null!=c.from&&c.from==c.to&&!1!==c.marker.clearWhenEmpty&&a.splice(b--,1)}return a.length?a:null}function fg(a,b,c){var d=null;if(a.iter(b.line,c.line+1,function(a){if(a.markedSpans)for(var b=0;b<a.markedSpans.length;++b){var c=
+a.markedSpans[b].marker;!c.readOnly||d&&-1!=N(d,c)||(d||(d=[])).push(c)}}),!d)return null;a=[{from:b,to:c}];for(b=0;b<d.length;++b){c=d[b];for(var e=c.find(0),f=0;f<a.length;++f){var g=a[f];if(!(0>x(g.to,e.from)||0<x(g.from,e.to))){var h=[f,1],k=x(g.from,e.from),l=x(g.to,e.to);(0>k||!c.inclusiveLeft&&!k)&&h.push({from:g.from,to:e.from});(0<l||!c.inclusiveRight&&!l)&&h.push({from:e.to,to:g.to});a.splice.apply(a,h);f+=h.length-3}}}return a}function Xd(a){var b=a.markedSpans;if(b){for(var c=0;c<b.length;++c)b[c].marker.detachLine(a);
+a.markedSpans=null}}function Yd(a,b){if(b){for(var c=0;c<b.length;++c)b[c].marker.attachLine(a);a.markedSpans=b}}function Zd(a,b){var c=a.lines.length-b.lines.length;if(0!=c)return c;var c=a.find(),d=b.find(),e=x(c.from,d.from)||(a.inclusiveLeft?-1:0)-(b.inclusiveLeft?-1:0);return e?-e:x(c.to,d.to)||(a.inclusiveRight?1:0)-(b.inclusiveRight?1:0)||b.id-a.id}function Ia(a,b){var c,d=xa&&a.markedSpans;if(d)for(var e=void 0,f=0;f<d.length;++f)e=d[f],e.marker.collapsed&&null==(b?e.from:e.to)&&(!c||0>Zd(c,
+e.marker))&&(c=e.marker);return c}function $d(a,b,c,d,e){a=w(a,b);if(a=xa&&a.markedSpans)for(b=0;b<a.length;++b){var f=a[b];if(f.marker.collapsed){var g=f.marker.find(0),h=x(g.from,c)||(f.marker.inclusiveLeft?-1:0)-(e.inclusiveLeft?-1:0),k=x(g.to,d)||(f.marker.inclusiveRight?1:0)-(e.inclusiveRight?1:0);if(!(0<=h&&0>=k||0>=h&&0<=k)&&(0>=h&&(f.marker.inclusiveRight&&e.inclusiveLeft?0<=x(g.to,c):0<x(g.to,c))||0<=h&&(f.marker.inclusiveRight&&e.inclusiveLeft?0>=x(g.from,d):0>x(g.from,d))))return!0}}}function ma(a){for(var b;b=
+Ia(a,!0);)a=b.find(-1,!0).line;return a}function Uc(a,b){var c=w(a,b),d=ma(c);return c==d?b:D(d)}function ae(a,b){if(b>a.lastLine())return b;var c,d=w(a,b);if(!Ja(a,d))return b;for(;c=Ia(d,!1);)d=c.find(1,!0).line;return D(d)+1}function Ja(a,b){var c=xa&&b.markedSpans;if(c)for(var d=void 0,e=0;e<c.length;++e)if(d=c[e],d.marker.collapsed)if(null==d.from||!d.marker.widgetNode&&0==d.from&&d.marker.inclusiveLeft&&Vc(a,b,d))return!0}function Vc(a,b,c){if(null==c.to)return b=c.marker.find(1,!0),Vc(a,b.line,
+tb(b.line.markedSpans,c.marker));if(c.marker.inclusiveRight&&c.to==b.text.length)return!0;for(var d=void 0,e=0;e<b.markedSpans.length;++e)if(d=b.markedSpans[e],d.marker.collapsed&&!d.marker.widgetNode&&d.from==c.to&&(null==d.to||d.to!=c.from)&&(d.marker.inclusiveLeft||c.marker.inclusiveRight)&&Vc(a,b,d))return!0}function na(a){a=ma(a);for(var b=0,c=a.parent,d=0;d<c.lines.length;++d){var e=c.lines[d];if(e==a)break;b+=e.height}for(a=c.parent;a;c=a,a=c.parent)for(d=0;d<a.children.length;++d){e=a.children[d];
+if(e==c)break;b+=e.height}return b}function kc(a){if(0==a.height)return 0;for(var b,c=a.text.length,d=a;b=Ia(d,!0);)b=b.find(0,!0),d=b.from.line,c+=b.from.ch-b.to.ch;for(d=a;b=Ia(d,!1);)a=b.find(0,!0),c-=d.text.length-a.from.ch,d=a.to.line,c+=d.text.length-a.to.ch;return c}function Wc(a){var b=a.display;a=a.doc;b.maxLine=w(a,a.first);b.maxLineLength=kc(b.maxLine);b.maxLineChanged=!0;a.iter(function(a){var d=kc(a);d>b.maxLineLength&&(b.maxLineLength=d,b.maxLine=a)})}function gg(a,b,c,d){if(!a)return d(b,
+c,"ltr");for(var e=!1,f=0;f<a.length;++f){var g=a[f];(g.from<c&&g.to>b||b==c&&g.to==b)&&(d(Math.max(g.from,b),Math.min(g.to,c),1==g.level?"rtl":"ltr"),e=!0)}e||d(b,c,"ltr")}function Xc(a,b,c){var d;ub=null;for(var e=0;e<a.length;++e){var f=a[e];if(f.from<b&&f.to>b)return e;f.to==b&&(f.from!=f.to&&"before"==c?d=e:ub=e);f.from==b&&(f.from!=f.to&&"before"!=c?d=e:ub=e)}return null!=d?d:ub}function ya(a,b){var c=a.order;return null==c&&(c=a.order=hg(a.text,b)),c}function Yc(a,b,c){b=Td(a.text,b+c,c);return 0>
+b||b>a.text.length?null:b}function Zc(a,b,c){a=Yc(a,b.ch,c);return null==a?null:new m(b.line,a,0>c?"after":"before")}function $c(a,b,c,d,e){if(a&&(a=ya(c,b.doc.direction))){var f=0>e?z(a):a[0],g=0>e==(1==f.level)?"after":"before";if(0<f.level){var h=$a(b,c);a=0>e?c.text.length-1:0;var k=ra(b,h,a).top;a=gc(function(a){return ra(b,h,a).top==k},0>e==(1==f.level)?f.from:f.to-1,a);"before"==g&&(a=Yc(c,a,1))}else a=0>e?f.to:f.from;return new m(d,a,g)}return new m(d,0>e?c.text.length:0,0>e?"before":"after")}
+function be(a,b,c,d){var e=ya(b,a.doc.direction);if(!e)return Zc(b,c,d);c.ch>=b.text.length?(c.ch=b.text.length,c.sticky="before"):0>=c.ch&&(c.ch=0,c.sticky="after");var f=Xc(e,c.ch,c.sticky),g=e[f];if("ltr"==a.doc.direction&&0==g.level%2&&(0<d?g.to>c.ch:g.from<c.ch))return Zc(b,c,d);var h,k=function(a,d){return Yc(b,a instanceof m?a.ch:a,d)},l=function(d){return a.options.lineWrapping?(h=h||$a(a,b),ce(a,b,h,Ka(a,b,ra(a,h,d),"line").top)):{begin:0,end:b.text.length}},n=l("before"==c.sticky?k(c,-1):
+c.ch);if("rtl"==a.doc.direction||1==g.level){var q=1==g.level==0>d,p=k(c,q?1:-1);if(null!=p&&(q?p<=g.to&&p<=n.end:p>=g.from&&p>=n.begin))return new m(c.line,p,q?"before":"after")}g=function(a,b,d){for(;0<=a&&a<e.length;a+=b){var f=e[a],g=0<b==(1!=f.level),h=g?d.begin:k(d.end,-1);if(f.from<=h&&h<f.to||(h=g?f.from:k(f.to,-1),d.begin<=h&&h<d.end))return a=h,g?new m(c.line,k(a,1),"before"):new m(c.line,a,"after")}};if(f=g(f+d,d,n))return f;n=0<d?n.end:k(n.begin,-1);return null==n||0<d&&n==b.text.length||
+!(f=g(0<d?0:e.length-1,d,l(n)))?null:f}function aa(a,b,c){if(a.removeEventListener)a.removeEventListener(b,c,!1);else if(a.detachEvent)a.detachEvent("on"+b,c);else{var d=(a=a._handlers)&&a[b];d&&(c=N(d,c),-1<c&&(a[b]=d.slice(0,c).concat(d.slice(c+1))))}}function F(a,b){var c=a._handlers&&a._handlers[b]||lc;if(c.length)for(var d=Array.prototype.slice.call(arguments,2),e=0;e<c.length;++e)c[e].apply(null,d)}function K(a,b,c){return"string"==typeof b&&(b={type:b,preventDefault:function(){this.defaultPrevented=
+!0}}),F(a,c||b.type,a,b),ad(b)||b.codemirrorIgnore}function de(a){var b=a._handlers&&a._handlers.cursorActivity;if(b){a=a.curOp.cursorActivityHandlers||(a.curOp.cursorActivityHandlers=[]);for(var c=0;c<b.length;++c)-1==N(a,b[c])&&a.push(b[c])}}function fa(a,b){return 0<(a._handlers&&a._handlers[b]||lc).length}function ab(a){a.prototype.on=function(a,c){t(this,a,c)};a.prototype.off=function(a,c){aa(this,a,c)}}function S(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function ee(a){a.stopPropagation?
+a.stopPropagation():a.cancelBubble=!0}function ad(a){return null!=a.defaultPrevented?a.defaultPrevented:0==a.returnValue}function vb(a){S(a);ee(a)}function fe(a){var b=a.which;return null==b&&(1&a.button?b=1:2&a.button?b=3:4&a.button&&(b=2)),ha&&a.ctrlKey&&1==b&&(b=3),b}function ig(a){if(null==bd){var b=r("span","​");Z(a,r("span",[b,document.createTextNode("x")]));0!=a.firstChild.offsetHeight&&(bd=1>=b.offsetWidth&&2<b.offsetHeight&&!(C&&8>B))}a=bd?r("span","​"):r("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");
+return a.setAttribute("cm-text",""),a}function jg(a,b){2<arguments.length&&(b.dependencies=Array.prototype.slice.call(arguments,2));cd[a]=b}function mc(a){if("string"==typeof a&&bb.hasOwnProperty(a))a=bb[a];else if(a&&"string"==typeof a.name&&bb.hasOwnProperty(a.name)){var b=bb[a.name];"string"==typeof b&&(b={name:b});a=Rd(b,a);a.name=b.name}else{if("string"==typeof a&&/^[\w\-]+\/[\w\-]+\+xml$/.test(a))return mc("application/xml");if("string"==typeof a&&/^[\w\-]+\/[\w\-]+\+json$/.test(a))return mc("application/json")}return"string"==
+typeof a?{name:a}:a||{name:"null"}}function dd(a,b){b=mc(b);var c=cd[b.name];if(!c)return dd(a,"text/plain");c=c(a,b);if(cb.hasOwnProperty(b.name)){var d=cb[b.name],e;for(e in d)d.hasOwnProperty(e)&&(c.hasOwnProperty(e)&&(c["_"+e]=c[e]),c[e]=d[e])}if(c.name=b.name,b.helperType&&(c.helperType=b.helperType),b.modeProps)for(var f in b.modeProps)c[f]=b.modeProps[f];return c}function kg(a,b){Fa(b,cb.hasOwnProperty(a)?cb[a]:cb[a]={})}function La(a,b){if(!0===b)return b;if(a.copyState)return a.copyState(b);
+var c={},d;for(d in b){var e=b[d];e instanceof Array&&(e=e.concat([]));c[d]=e}return c}function ed(a,b){for(var c;a.innerMode&&(c=a.innerMode(b))&&c.mode!=a;)b=c.state,a=c.mode;return c||{mode:a,state:b}}function ge(a,b,c){return!a.startState||a.startState(b,c)}function he(a,b,c,d){var e=[a.state.modeGen],f={};ie(a,b.text,a.doc.mode,c,function(a,b){return e.push(a,b)},f,d);d=c.state;for(var g=0;g<a.state.overlays.length;++g)!function(d){var g=a.state.overlays[d],l=1,n=0;c.state=!0;ie(a,b.text,g.mode,
+c,function(a,b){for(var d=l;n<a;){var c=e[l];c>a&&e.splice(l,1,a,e[l+1],c);l+=2;n=Math.min(a,c)}if(b)if(g.opaque)e.splice(d,l-d,a,"overlay "+b),l=d+2;else for(;d<l;d+=2)c=e[d+1],e[d+1]=(c?c+" ":"")+"overlay "+b},f)}(g);return c.state=d,{styles:e,classes:f.bgClass||f.textClass?f:null}}function je(a,b,c){if(!b.styles||b.styles[0]!=a.state.modeGen){var d=wb(a,D(b)),e=b.text.length>a.options.maxHighlightLength&&La(a.doc.mode,d.state),f=he(a,b,d);e&&(d.state=e);b.stateAfter=d.save(!e);b.styles=f.styles;
+f.classes?b.styleClasses=f.classes:b.styleClasses&&(b.styleClasses=null);c===a.doc.highlightFrontier&&(a.doc.modeFrontier=Math.max(a.doc.modeFrontier,++a.doc.highlightFrontier))}return b.styles}function wb(a,b,c){var d=a.doc,e=a.display;if(!d.mode.startState)return new sa(d,!0,b);var f=lg(a,b,c),g=f>d.first&&w(d,f-1).stateAfter,h=g?sa.fromSaved(d,g,f):new sa(d,ge(d.mode),f);return d.iter(f,b,function(d){fd(a,d.text,h);var c=h.line;d.stateAfter=c==b-1||0==c%5||c>=e.viewFrom&&c<e.viewTo?h.save():null;
+h.nextLine()}),c&&(d.modeFrontier=h.line),h}function fd(a,b,c,d){var e=a.doc.mode;a=new H(b,a.options.tabSize,c);a.start=a.pos=d||0;for(""==b&&ke(e,c.state);!a.eol();)gd(e,a,c.state),a.start=a.pos}function ke(a,b){if(a.blankLine)return a.blankLine(b);if(a.innerMode){var c=ed(a,b);return c.mode.blankLine?c.mode.blankLine(c.state):void 0}}function gd(a,b,c,d){for(var e=0;10>e;e++){d&&(d[0]=ed(a,c).mode);var f=a.token(b,c);if(b.pos>b.start)return f}throw Error("Mode "+a.name+" failed to advance stream.");
+}function le(a,b,c,d){var e,f=a.doc,g=f.mode;b=v(f,b);var h,k=w(f,b.line);c=wb(a,b.line,c);a=new H(k.text,a.options.tabSize,c);for(d&&(h=[]);(d||a.pos<b.ch)&&!a.eol();)a.start=a.pos,e=gd(g,a,c.state),d&&h.push(new me(a,e,La(f.mode,c.state)));return d?h:new me(a,e,c.state)}function ne(a,b){if(a)for(;;){var c=a.match(/(?:^|\s+)line-(background-)?(\S+)/);if(!c)break;a=a.slice(0,c.index)+a.slice(c.index+c[0].length);var d=c[1]?"bgClass":"textClass";null==b[d]?b[d]=c[2]:(new RegExp("(?:^|s)"+c[2]+"(?:$|s)")).test(b[d])||
+(b[d]+=" "+c[2])}return a}function ie(a,b,c,d,e,f,g){var h=c.flattenSpans;null==h&&(h=a.options.flattenSpans);var k,l=0,n=null,q=new H(b,a.options.tabSize,d),p=a.options.addModeClass&&[null];for(""==b&&ne(ke(c,d.state),f);!q.eol();){if(q.pos>a.options.maxHighlightLength?(h=!1,g&&fd(a,b,d,q.pos),q.pos=b.length,k=null):k=ne(gd(c,q,d.state,p),f),p){var u=p[0].name;u&&(k="m-"+(k?u+" "+k:u))}if(!h||n!=k){for(;l<q.start;)l=Math.min(q.start,l+5E3),e(l,n);n=k}q.start=q.pos}for(;l<q.pos;)a=Math.min(q.pos,
+l+5E3),e(a,n),l=a}function lg(a,b,c){for(var d,e,f=a.doc,g=c?-1:b-(a.doc.mode.innerMode?1E3:100);b>g;--b){if(b<=f.first)return f.first;var h=w(f,b-1),k=h.stateAfter;if(k&&(!c||b+(k instanceof nc?k.lookAhead:0)<=f.modeFrontier))return b;h=ea(h.text,null,a.options.tabSize);(null==e||d>h)&&(e=b-1,d=h)}return e}function mg(a,b){if(a.modeFrontier=Math.min(a.modeFrontier,b),!(a.highlightFrontier<b-10)){for(var c=a.first,d=b-1;d>c;d--){var e=w(a,d).stateAfter;if(e&&(!(e instanceof nc)||d+e.lookAhead<b)){c=
+d+1;break}}a.highlightFrontier=Math.min(a.highlightFrontier,c)}}function oe(a,b){if(!a||/^\s*$/.test(a))return null;var c=b.addModeClass?ng:og;return c[a]||(c[a]=a.replace(/\S+/g,"cm-$\x26"))}function pe(a,b){var c=Za("span",null,null,R?"padding-right: .1px":null),c={pre:Za("pre",[c],"CodeMirror-line"),content:c,col:0,pos:0,cm:a,trailingSpace:!1,splitSpaces:(C||R)&&a.getOption("lineWrapping")};b.measure={};for(var d=0;d<=(b.rest?b.rest.length:0);d++){var e=d?b.rest[d-1]:b.line,f=void 0;c.pos=0;c.addToken=
+pg;var g;g=a.display.measure;if(null!=hd)g=hd;else{var h=Z(g,document.createTextNode("AخA")),k=db(h,0,1).getBoundingClientRect(),h=db(h,1,2).getBoundingClientRect();g=(X(g),!(!k||k.left==k.right)&&(hd=3>h.right-k.right))}g&&(f=ya(e,a.doc.direction))&&(c.addToken=qg(c.addToken,f));c.map=[];a:{f=c;g=je(a,e,b!=a.display.externalMeasured&&D(e));var l=e.markedSpans,k=e.text,h=0;if(l)for(var n=void 0,q=void 0,p=void 0,u=void 0,O=void 0,m=void 0,J=void 0,w=k.length,G=0,r=1,t="",x=0;;){if(x==G){for(var p=
+u=O=m=q="",J=null,x=1/0,v=[],z=void 0,A=0;A<l.length;++A){var y=l[A],B=y.marker;"bookmark"==B.type&&y.from==G&&B.widgetNode?v.push(B):y.from<=G&&(null==y.to||y.to>G||B.collapsed&&y.to==G&&y.from==G)?(null!=y.to&&y.to!=G&&x>y.to&&(x=y.to,u=""),B.className&&(p+=" "+B.className),B.css&&(q=(q?q+";":"")+B.css),B.startStyle&&y.from==G&&(O+=" "+B.startStyle),B.endStyle&&y.to==x&&(z||(z=[])).push(B.endStyle,y.to),B.title&&!m&&(m=B.title),B.collapsed&&(!J||0>Zd(J.marker,B))&&(J=y)):y.from>G&&x>y.from&&(x=
+y.from)}if(z)for(A=0;A<z.length;A+=2)z[A+1]==x&&(u+=" "+z[A]);if(!J||J.from==G)for(z=0;z<v.length;++z)qe(f,0,v[z]);if(J&&(J.from||0)==G){if(qe(f,(null==J.to?w+1:J.to)-G,J.marker,null==J.from),null==J.to)break a;J.to==G&&(J=!1)}}if(G>=w)break;for(v=Math.min(w,x);;){if(t){z=G+t.length;J||(A=z>v?t.slice(0,v-G):t,f.addToken(f,A,n?n+p:p,O,G+A.length==x?u:"",m,q));if(z>=v){t=t.slice(v-G);G=v;break}G=z;O=""}t=k.slice(h,h=g[r++]);n=oe(g[r++],f.cm.options)}}else for(l=1;l<g.length;l+=2)f.addToken(f,k.slice(h,
+h=g[l]),oe(g[l+1],f.cm.options))}e.styleClasses&&(e.styleClasses.bgClass&&(c.bgClass=Jc(e.styleClasses.bgClass,c.bgClass||"")),e.styleClasses.textClass&&(c.textClass=Jc(e.styleClasses.textClass,c.textClass||"")));0==c.map.length&&c.map.push(0,0,c.content.appendChild(ig(a.display.measure)));0==d?(b.measure.map=c.map,b.measure.cache={}):((b.measure.maps||(b.measure.maps=[])).push(c.map),(b.measure.caches||(b.measure.caches=[])).push({}))}R&&(d=c.content.lastChild,(/\bcm-tab\b/.test(d.className)||d.querySelector&&
+d.querySelector(".cm-tab"))&&(c.content.className="cm-tab-wrap-hack"));return F(a,"renderLine",a,b.line,c.pre),c.pre.className&&(c.textClass=Jc(c.pre.className,c.textClass||"")),c}function rg(a){var b=r("span","•","cm-invalidchar");return b.title="\\u"+a.charCodeAt(0).toString(16),b.setAttribute("aria-label",b.title),b}function pg(a,b,c,d,e,f,g){if(b){var h;if(a.splitSpaces)if(h=a.trailingSpace,1<b.length&&!/  /.test(b))h=b;else{for(var k="",l=0;l<b.length;l++){var n=b.charAt(l);" "!=n||!h||l!=b.length-
+1&&32!=b.charCodeAt(l+1)||(n=" ");k+=n;h=" "==n}h=k}else h=b;k=h;l=a.cm.state.specialChars;n=!1;if(l.test(b)){h=document.createDocumentFragment();for(var q=0;;){l.lastIndex=q;var p=l.exec(b),u=p?p.index-q:b.length-q;if(u){var O=document.createTextNode(k.slice(q,q+u));C&&9>B?h.appendChild(r("span",[O])):h.appendChild(O);a.map.push(a.pos,a.pos+u,O);a.col+=u;a.pos+=u}if(!p)break;q+=u+1;u=void 0;"\t"==p[0]?(p=a.cm.options.tabSize,p-=a.col%p,u=h.appendChild(r("span",Mc(p),"cm-tab")),u.setAttribute("role",
+"presentation"),u.setAttribute("cm-text","\t"),a.col+=p):"\r"==p[0]||"\n"==p[0]?(u=h.appendChild(r("span","\r"==p[0]?"␍":"␤","cm-invalidchar")),u.setAttribute("cm-text",p[0]),a.col+=1):(u=a.cm.options.specialCharPlaceholder(p[0]),u.setAttribute("cm-text",p[0]),C&&9>B?h.appendChild(r("span",[u])):h.appendChild(u),a.col+=1);a.map.push(a.pos,a.pos+1,u);a.pos++}}else a.col+=b.length,h=document.createTextNode(k),a.map.push(a.pos,a.pos+b.length,h),C&&9>B&&(n=!0),a.pos+=b.length;if(a.trailingSpace=32==k.charCodeAt(b.length-
+1),c||d||e||n||g)return b=c||"",d&&(b+=d),e&&(b+=e),d=r("span",[h],b,g),f&&(d.title=f),a.content.appendChild(d);a.content.appendChild(h)}}function qg(a,b){return function(c,d,e,f,g,h,k){e=e?e+" cm-force-border":"cm-force-border";for(var l=c.pos,n=l+d.length;;){for(var q=void 0,p=0;p<b.length&&(q=b[p],!(q.to>l&&q.from<=l));p++);if(q.to>=n)return a(c,d,e,f,g,h,k);a(c,d.slice(0,q.to-l),e,f,null,h,k);f=null;d=d.slice(q.to-l);l=q.to}}}function qe(a,b,c,d){var e=!d&&c.widgetNode;e&&a.map.push(a.pos,a.pos+
+b,e);!d&&a.cm.display.input.needsContentAttribute&&(e||(e=a.content.appendChild(document.createElement("span"))),e.setAttribute("cm-marker",c.id));e&&(a.cm.display.input.setUneditable(e),a.content.appendChild(e));a.pos+=b;a.trailingSpace=!1}function re(a,b,c){for(var d=this.line=b,e;d=Ia(d,!1);)d=d.find(1,!0).line,(e||(e=[])).push(d);this.size=(this.rest=e)?D(z(this.rest))-c+1:1;this.node=this.text=null;this.hidden=Ja(a,b)}function oc(a,b,c){var d,e=[];for(d=b;d<c;)b=new re(a.doc,w(a.doc,d),d),d+=
+b.size,e.push(b);return e}function sg(a,b){var c=a.ownsGroup;if(c)try{var d=c.delayedCallbacks,e=0;do{for(;e<d.length;e++)d[e].call(null);for(var f=0;f<c.ops.length;f++){var g=c.ops[f];if(g.cursorActivityHandlers)for(;g.cursorActivityCalled<g.cursorActivityHandlers.length;)g.cursorActivityHandlers[g.cursorActivityCalled++].call(null,g.cm)}}while(e<d.length)}finally{eb=null,b(c)}}function P(a,b){var c=a._handlers&&a._handlers[b]||lc;if(c.length){var d,e=Array.prototype.slice.call(arguments,2);eb?d=
+eb.delayedCallbacks:xb?d=xb:(d=xb=[],setTimeout(tg,0));for(var f=0;f<c.length;++f)!function(a){d.push(function(){return c[a].apply(null,e)})}(f)}}function tg(){var a=xb;xb=null;for(var b=0;b<a.length;++b)a[b]()}function se(a,b,c,d){for(var e=0;e<b.changes.length;e++){var f=b.changes[e];if("text"==f){var f=a,g=b,h=g.text.className,k=te(f,g);g.text==g.node&&(g.node=k.pre);g.text.parentNode.replaceChild(k.pre,g.text);g.text=k.pre;k.bgClass!=g.bgClass||k.textClass!=g.textClass?(g.bgClass=k.bgClass,g.textClass=
+k.textClass,id(f,g)):h&&(g.text.className=h)}else if("gutter"==f)ue(a,b,c,d);else if("class"==f)id(a,b);else if("widget"==f){f=a;g=b;h=d;g.alignable&&(g.alignable=null);for(var k=g.node.firstChild,l=void 0;k;k=l)l=k.nextSibling,"CodeMirror-linewidget"==k.className&&g.node.removeChild(k);ve(f,g,h)}}b.changes=null}function yb(a){return a.node==a.text&&(a.node=r("div",null,null,"position: relative"),a.text.parentNode&&a.text.parentNode.replaceChild(a.node,a.text),a.node.appendChild(a.text),C&&8>B&&(a.node.style.zIndex=
+2)),a.node}function te(a,b){var c=a.display.externalMeasured;return c&&c.line==b.line?(a.display.externalMeasured=null,b.measure=c.measure,c.built):pe(a,b)}function id(a,b){var c=b.bgClass?b.bgClass+" "+(b.line.bgClass||""):b.line.bgClass;if(c&&(c+=" CodeMirror-linebackground"),b.background)c?b.background.className=c:(b.background.parentNode.removeChild(b.background),b.background=null);else if(c){var d=yb(b);b.background=d.insertBefore(r("div",null,c),d.firstChild);a.display.input.setUneditable(b.background)}b.line.wrapClass?
+yb(b).className=b.line.wrapClass:b.node!=b.text&&(b.node.className="");b.text.className=(b.textClass?b.textClass+" "+(b.line.textClass||""):b.line.textClass)||""}function ue(a,b,c,d){if(b.gutter&&(b.node.removeChild(b.gutter),b.gutter=null),b.gutterBackground&&(b.node.removeChild(b.gutterBackground),b.gutterBackground=null),b.line.gutterClass){var e=yb(b);b.gutterBackground=r("div",null,"CodeMirror-gutter-background "+b.line.gutterClass,"left: "+(a.options.fixedGutter?d.fixedPos:-d.gutterTotalWidth)+
+"px; width: "+d.gutterTotalWidth+"px");a.display.input.setUneditable(b.gutterBackground);e.insertBefore(b.gutterBackground,b.text)}e=b.line.gutterMarkers;if(a.options.lineNumbers||e){var f=yb(b),g=b.gutter=r("div",null,"CodeMirror-gutter-wrapper","left: "+(a.options.fixedGutter?d.fixedPos:-d.gutterTotalWidth)+"px");if(a.display.input.setUneditable(g),f.insertBefore(g,b.text),b.line.gutterClass&&(g.className+=" "+b.line.gutterClass),!a.options.lineNumbers||e&&e["CodeMirror-linenumbers"]||(b.lineNumber=
+g.appendChild(r("div",Qc(a.options,c),"CodeMirror-linenumber CodeMirror-gutter-elt","left: "+d.gutterLeft["CodeMirror-linenumbers"]+"px; width: "+a.display.lineNumInnerWidth+"px"))),e)for(b=0;b<a.options.gutters.length;++b)c=a.options.gutters[b],(f=e.hasOwnProperty(c)&&e[c])&&g.appendChild(r("div",[f],"CodeMirror-gutter-elt","left: "+d.gutterLeft[c]+"px; width: "+d.gutterWidth[c]+"px"))}}function ug(a,b,c,d){var e=te(a,b);return b.text=b.node=e.pre,e.bgClass&&(b.bgClass=e.bgClass),e.textClass&&(b.textClass=
+e.textClass),id(a,b),ue(a,b,c,d),ve(a,b,d),b.node}function ve(a,b,c){if(we(a,b.line,b,c,!0),b.rest)for(var d=0;d<b.rest.length;d++)we(a,b.rest[d],b,c,!1)}function we(a,b,c,d,e){if(b.widgets){var f=yb(c),g=0;for(b=b.widgets;g<b.length;++g){var h=b[g],k=r("div",[h.node],"CodeMirror-linewidget");h.handleMouseEvents||k.setAttribute("cm-ignore-events","true");var l=h,n=k,q=d;if(l.noHScroll){(c.alignable||(c.alignable=[])).push(n);var p=q.wrapperWidth;n.style.left=q.fixedPos+"px";l.coverGutter||(p-=q.gutterTotalWidth,
+n.style.paddingLeft=q.gutterTotalWidth+"px");n.style.width=p+"px"}l.coverGutter&&(n.style.zIndex=5,n.style.position="relative",l.noHScroll||(n.style.marginLeft=-q.gutterTotalWidth+"px"));a.display.input.setUneditable(k);e&&h.above?f.insertBefore(k,c.gutter||c.text):f.appendChild(k);P(h,"redraw")}}}function zb(a){if(null!=a.height)return a.height;var b=a.doc.cm;if(!b)return 0;if(!va(document.body,a.node)){var c="position: relative;";a.coverGutter&&(c+="margin-left: -"+b.display.gutters.offsetWidth+
+"px;");a.noHScroll&&(c+="width: "+b.display.wrapper.clientWidth+"px;");Z(b.display.measure,r("div",[a.node],null,c))}return a.height=a.node.parentNode.offsetHeight}function ta(a,b){for(var c=b.target||b.srcElement;c!=a.wrapper;c=c.parentNode)if(!c||1==c.nodeType&&"true"==c.getAttribute("cm-ignore-events")||c.parentNode==a.sizer&&c!=a.mover)return!0}function jd(a){return a.mover.offsetHeight-a.lineSpace.offsetHeight}function xe(a){if(a.cachedPaddingH)return a.cachedPaddingH;var b=Z(a.measure,r("pre",
+"x")),b=window.getComputedStyle?window.getComputedStyle(b):b.currentStyle,b={left:parseInt(b.paddingLeft),right:parseInt(b.paddingRight)};return isNaN(b.left)||isNaN(b.right)||(a.cachedPaddingH=b),b}function oa(a){return Ud-a.display.nativeBarWidth}function Ma(a){return a.display.scroller.clientWidth-oa(a)-a.display.barWidth}function kd(a){return a.display.scroller.clientHeight-oa(a)-a.display.barHeight}function ye(a,b,c){if(a.line==b)return{map:a.measure.map,cache:a.measure.cache};for(var d=0;d<
+a.rest.length;d++)if(a.rest[d]==b)return{map:a.measure.maps[d],cache:a.measure.caches[d]};for(b=0;b<a.rest.length;b++)if(D(a.rest[b])>c)return{map:a.measure.maps[b],cache:a.measure.caches[b],before:!0}}function ld(a,b){if(b>=a.display.viewFrom&&b<a.display.viewTo)return a.display.view[Na(a,b)];var c=a.display.externalMeasured;return c&&b>=c.lineN&&b<c.lineN+c.size?c:void 0}function $a(a,b){var c=D(b),d=ld(a,c);d&&!d.text?d=null:d&&d.changes&&(se(a,d,c,md(a)),a.curOp.forceUpdate=!0);if(!d){var e;e=
+ma(b);d=D(e);e=a.display.externalMeasured=new re(a.doc,e,d);e.lineN=d;d=e.built=pe(a,e);d=(e.text=d.pre,Z(a.display.lineMeasure,d.pre),e)}c=ye(d,b,c);return{line:b,view:d,rect:null,map:c.map,cache:c.cache,before:c.before,hasHeights:!1}}function ra(a,b,c,d,e){b.before&&(c=-1);var f=c+(d||"");if(b.cache.hasOwnProperty(f))a=b.cache[f];else{b.rect||(b.rect=b.view.text.getBoundingClientRect());if(!b.hasHeights){var g=b.view,h=b.rect,k=a.options.lineWrapping,l=k&&Ma(a);if(!g.measure.heights||k&&g.measure.width!=
+l){var n=g.measure.heights=[];if(k)for(g.measure.width=l,g=g.text.firstChild.getClientRects(),k=0;k<g.length-1;k++){var l=g[k],q=g[k+1];2<Math.abs(l.bottom-q.bottom)&&n.push((l.bottom+q.top)/2-h.top)}n.push(h.bottom-h.top)}b.hasHeights=!0}var n=d,p,g=ze(b.map,c,n);d=g.node;h=g.start;k=g.end;c=g.collapse;if(3==d.nodeType){for(var u=0;4>u;u++){for(;h&&Oc(b.line.text.charAt(g.coverStart+h));)--h;for(;g.coverStart+k<g.coverEnd&&Oc(b.line.text.charAt(g.coverStart+k));)++k;if(C&&9>B&&0==h&&k==g.coverEnd-
+g.coverStart)k=d.parentNode.getBoundingClientRect();else{k=db(d,h,k).getClientRects();l=Ae;if("left"==n)for(q=0;q<k.length&&(l=k[q]).left==l.right;q++);else for(q=k.length-1;0<=q&&(l=k[q]).left==l.right;q--);k=l}if(p=k,p.left||p.right||0==h)break;k=h;--h;c="right"}C&&11>B&&((u=!window.screen||null==screen.logicalXDPI||screen.logicalXDPI==screen.deviceXDPI)||(null!=nd?u=nd:(n=Z(a.display.measure,r("span","x")),u=n.getBoundingClientRect(),n=db(n,0,1).getBoundingClientRect(),u=nd=1<Math.abs(u.left-n.left)),
+u=!u),u||(u=screen.logicalXDPI/screen.deviceXDPI,n=screen.logicalYDPI/screen.deviceYDPI,p={left:p.left*u,right:p.right*u,top:p.top*n,bottom:p.bottom*n}))}else 0<h&&(c=n="right"),p=a.options.lineWrapping&&1<(u=d.getClientRects()).length?u["right"==n?u.length-1:0]:d.getBoundingClientRect();!(C&&9>B)||h||p&&(p.left||p.right)||(p=(p=d.parentNode.getClientRects()[0])?{left:p.left,right:p.left+Ab(a.display),top:p.top,bottom:p.bottom}:Ae);d=p.top-b.rect.top;h=p.bottom-b.rect.top;u=(d+h)/2;n=b.view.measure.heights;
+for(g=0;g<n.length-1&&!(u<n[g]);g++);c={left:("right"==c?p.right:p.left)-b.rect.left,right:("left"==c?p.left:p.right)-b.rect.left,top:g?n[g-1]:0,bottom:n[g]};a=(p.left||p.right||(c.bogus=!0),a.options.singleCursorHeightPerLine||(c.rtop=d,c.rbottom=h),c);a.bogus||(b.cache[f]=a)}return{left:a.left,right:a.right,top:e?a.rtop:a.top,bottom:e?a.rbottom:a.bottom}}function ze(a,b,c){for(var d,e,f,g,h,k,l=0;l<a.length;l+=3)if(h=a[l],k=a[l+1],b<h?(e=0,f=1,g="left"):b<k?(e=b-h,f=e+1):(l==a.length-3||b==k&&a[l+
+3]>b)&&(f=k-h,e=f-1,b>=k&&(g="right")),null!=e){if(d=a[l+2],h==k&&c==(d.insertLeft?"left":"right")&&(g=c),"left"==c&&0==e)for(;l&&a[l-2]==a[l-3]&&a[l-1].insertLeft;)d=a[2+(l-=3)],g="left";if("right"==c&&e==k-h)for(;l<a.length-3&&a[l+3]==a[l+4]&&!a[l+5].insertLeft;)d=a[(l+=3)+2],g="right";break}return{node:d,start:e,end:f,collapse:g,coverStart:h,coverEnd:k}}function Be(a){if(a.measure&&(a.measure.cache={},a.measure.heights=null,a.rest))for(var b=0;b<a.rest.length;b++)a.measure.caches[b]={}}function Ce(a){a.display.externalMeasure=
+null;X(a.display.lineMeasure);for(var b=0;b<a.display.view.length;b++)Be(a.display.view[b])}function Bb(a){Ce(a);a.display.cachedCharWidth=a.display.cachedTextHeight=a.display.cachedPaddingH=null;a.options.lineWrapping||(a.display.maxLineChanged=!0);a.display.lineNumChars=null}function De(){return pc&&qc?-(document.body.getBoundingClientRect().left-parseInt(getComputedStyle(document.body).marginLeft)):window.pageXOffset||(document.documentElement||document.body).scrollLeft}function Ee(){return pc&&
+qc?-(document.body.getBoundingClientRect().top-parseInt(getComputedStyle(document.body).marginTop)):window.pageYOffset||(document.documentElement||document.body).scrollTop}function Ka(a,b,c,d,e){if(!e&&b.widgets)for(e=0;e<b.widgets.length;++e)if(b.widgets[e].above){var f=zb(b.widgets[e]);c.top+=f;c.bottom+=f}if("line"==d)return c;d||(d="local");b=na(b);if("local"==d?b+=a.display.lineSpace.offsetTop:b-=a.display.viewOffset,"page"==d||"window"==d)a=a.display.lineSpace.getBoundingClientRect(),b+=a.top+
+("window"==d?0:Ee()),d=a.left+("window"==d?0:De()),c.left+=d,c.right+=d;return c.top+=b,c.bottom+=b,c}function Fe(a,b,c){if("div"==c)return b;var d=b.left;b=b.top;"page"==c?(d-=De(),b-=Ee()):"local"!=c&&c||(c=a.display.sizer.getBoundingClientRect(),d+=c.left,b+=c.top);a=a.display.lineSpace.getBoundingClientRect();return{left:d-a.left,top:b-a.top}}function rc(a,b,c,d,e){d||(d=w(a.doc,b.line));var f=d;b=b.ch;d=ra(a,$a(a,d),b,e);return Ka(a,f,d,c)}function ia(a,b,c,d,e,f){function g(b,g){var h=ra(a,
+e,b,g?"right":"left",f);return g?h.left=h.right:h.right=h.left,Ka(a,d,h,c)}function h(a,b,d){return g(d?a-1:a,0!=k[b].level%2!=d)}d=d||w(a.doc,b.line);e||(e=$a(a,d));var k=ya(d,a.doc.direction),l=b.ch;b=b.sticky;if(l>=d.text.length?(l=d.text.length,b="before"):0>=l&&(l=0,b="after"),!k)return g("before"==b?l-1:l,"before"==b);var n=Xc(k,l,b),q=ub,n=h(l,n,"before"==b);return null!=q&&(n.other=h(l,q,"before"!=b)),n}function Ge(a,b){var c=0;b=v(a.doc,b);a.options.lineWrapping||(c=Ab(a.display)*b.ch);var d=
+w(a.doc,b.line),e=na(d)+a.display.lineSpace.offsetTop;return{left:c,right:c,top:e,bottom:e+d.height}}function od(a,b,c){var d=a.doc;if(0>(c+=a.display.viewOffset))return a=m(d.first,0,null),a.xRel=-1,a.outside=!0,a;var e=Ha(d,c),f=d.first+d.size-1;if(e>f)return a=w(d,f).text.length,a=m(d.first+d.size-1,a,null),a.xRel=1,a.outside=!0,a;0>b&&(b=0);for(f=w(d,e);;){d=vg(a,f,e,b,c);f=(e=Ia(f,!1))&&e.find(0,!0);if(!e||!(d.ch>f.from.ch||d.ch==f.from.ch&&0<d.xRel))return d;e=D(f=f.to.line)}}function ce(a,
+b,c,d){var e=b.text.length,f=gc(function(e){return Ka(a,b,ra(a,c,e-1),"line").bottom<=d},e,0);return e=gc(function(e){return Ka(a,b,ra(a,c,e),"line").top>d},f,e),{begin:f,end:e}}function vg(a,b,c,d,e){e-=na(b);var f=0,g=b.text.length,h=$a(a,b);if(ya(b,a.doc.direction)){if(a.options.lineWrapping){var k;k=ce(a,b,h,e);f=k.begin;g=k.end}c=new m(c,Math.floor(f+(g-f)/2));var l;k=ia(a,c,"line",b,h).left;var n=k<d?1:-1,q=k-d,p=Math.ceil((g-f)/4);a:do{k=q;l=c;for(var u=0;u<p;++u){var O=c;if(null==(c=be(a,
+b,c,n))||c.ch<f||g<=("before"==c.sticky?c.ch-1:c.ch)){c=O;break a}}if(q=ia(a,c,"line",b,h).left-d,1<p)n=Math.abs(q-k)/p,p=Math.min(p,Math.ceil(Math.abs(q)/n)),n=0>q?1:-1}while(0!=q&&(1<p||0>n!=0>q&&Math.abs(q)<=Math.abs(k)));if(Math.abs(q)>Math.abs(k)){if(0>q==0>k)throw Error("Broke out of infinite loop in coordsCharInner");c=l}}else f=gc(function(c){var f=Ka(a,b,ra(a,h,c),"line");return f.top>e?(g=Math.min(c,g),!0):!(f.bottom<=e)&&(f.left>d||!(f.right<d)&&d-f.left<f.right-d)},f,g),f=Td(b.text,f,
+1),c=new m(c,f,f==g?"before":"after");f=ia(a,c,"line",b,h);return(e<f.top||f.bottom<e)&&(c.outside=!0),c.xRel=d<f.left?-1:d>f.right?1:0,c}function Oa(a){if(null!=a.cachedTextHeight)return a.cachedTextHeight;if(null==Pa){Pa=r("pre");for(var b=0;49>b;++b)Pa.appendChild(document.createTextNode("x")),Pa.appendChild(r("br"));Pa.appendChild(document.createTextNode("x"))}Z(a.measure,Pa);b=Pa.offsetHeight/50;return 3<b&&(a.cachedTextHeight=b),X(a.measure),b||1}function Ab(a){if(null!=a.cachedCharWidth)return a.cachedCharWidth;
+var b=r("span","xxxxxxxxxx"),c=r("pre",[b]);Z(a.measure,c);b=b.getBoundingClientRect();b=(b.right-b.left)/10;return 2<b&&(a.cachedCharWidth=b),b||10}function md(a){for(var b=a.display,c={},d={},e=b.gutters.clientLeft,f=b.gutters.firstChild,g=0;f;f=f.nextSibling,++g)c[a.options.gutters[g]]=f.offsetLeft+f.clientLeft+e,d[a.options.gutters[g]]=f.clientWidth;return{fixedPos:pd(b),gutterTotalWidth:b.gutters.offsetWidth,gutterLeft:c,gutterWidth:d,wrapperWidth:b.wrapper.clientWidth}}function pd(a){return a.scroller.getBoundingClientRect().left-
+a.sizer.getBoundingClientRect().left}function He(a){var b=Oa(a.display),c=a.options.lineWrapping,d=c&&Math.max(5,a.display.scroller.clientWidth/Ab(a.display)-3);return function(e){if(Ja(a.doc,e))return 0;var f=0;if(e.widgets)for(var g=0;g<e.widgets.length;g++)e.widgets[g].height&&(f+=e.widgets[g].height);return c?f+(Math.ceil(e.text.length/d)||1)*b:f+b}}function qd(a){var b=a.doc,c=He(a);b.iter(function(a){var b=c(a);b!=a.height&&la(a,b)})}function Qa(a,b,c,d){var e=a.display;if(!c&&"true"==(b.target||
+b.srcElement).getAttribute("cm-not-content"))return null;var f,g;c=e.lineSpace.getBoundingClientRect();try{f=b.clientX-c.left,g=b.clientY-c.top}catch(h){return null}var k;b=od(a,f,g);d&&1==b.xRel&&(k=w(a.doc,b.line).text).length==b.ch&&(d=ea(k,k.length,a.options.tabSize)-k.length,b=m(b.line,Math.max(0,Math.round((f-xe(a.display).left)/Ab(a.display))-d)));return b}function Na(a,b){if(b>=a.display.viewTo||0>(b-=a.display.viewFrom))return null;for(var c=a.display.view,d=0;d<c.length;d++)if(0>(b-=c[d].size))return d}
+function Cb(a){a.display.input.showSelection(a.display.input.prepareSelection())}function Ie(a,b){for(var c=a.doc,d={},e=d.cursors=document.createDocumentFragment(),f=d.selection=document.createDocumentFragment(),g=0;g<c.sel.ranges.length;g++)if(!1!==b||g!=c.sel.primIndex){var h=c.sel.ranges[g];if(!(h.from().line>=a.display.viewTo||h.to().line<a.display.viewFrom)){var k=h.empty();(k||a.options.showCursorWhenSelecting)&&Je(a,h.head,e);k||wg(a,h,f)}}return d}function Je(a,b,c){b=ia(a,b,"div",null,null,
+!a.options.singleCursorHeightPerLine);var d=c.appendChild(r("div"," ","CodeMirror-cursor"));if(d.style.left=b.left+"px",d.style.top=b.top+"px",d.style.height=Math.max(0,b.bottom-b.top)*a.options.cursorHeight+"px",b.other)a=c.appendChild(r("div"," ","CodeMirror-cursor CodeMirror-secondarycursor")),a.style.display="",a.style.left=b.other.left+"px",a.style.top=b.other.top+"px",a.style.height=.85*(b.other.bottom-b.other.top)+"px"}function wg(a,b,c){function d(a,b,d,c){0>b&&(b=0);b=Math.round(b);c=Math.round(c);
+h.appendChild(r("div",null,"CodeMirror-selected","position: absolute; left: "+a+"px;\n                             top: "+b+"px; width: "+(null==d?n-a:d)+"px;\n                             height: "+(c-b)+"px"))}function e(b,c,e){var f,h,k=w(g,b),q=k.text.length;return gg(ya(k,g.direction),c||0,null==e?q:e,function(g,w,t){var r,x,v=rc(a,m(b,g),"div",k,"left");if(g==w)r=v,t=x=v.left;else{if(r=rc(a,m(b,w-1),"div",k,"right"),"rtl"==t)t=v,v=r,r=t;t=v.left;x=r.right}null==c&&0==g&&(t=l);3<r.top-v.top&&
+(d(t,v.top,null,v.bottom),t=l,v.bottom<r.top&&d(t,v.bottom,null,r.top));null==e&&w==q&&(x=n);(!f||v.top<f.top||v.top==f.top&&v.left<f.left)&&(f=v);(!h||r.bottom>h.bottom||r.bottom==h.bottom&&r.right>h.right)&&(h=r);t<l+1&&(t=l);d(t,r.top,x-t,r.bottom)}),{start:f,end:h}}var f=a.display,g=a.doc,h=document.createDocumentFragment(),k=xe(a.display),l=k.left,n=Math.max(f.sizerWidth,Ma(a)-f.sizer.offsetLeft)-k.right,f=b.from();b=b.to();if(f.line==b.line)e(f.line,f.ch,b.ch);else{var q=w(g,f.line),k=w(g,b.line),
+k=ma(q)==ma(k),f=e(f.line,f.ch,k?q.text.length+1:null).end;b=e(b.line,k?0:null,b.ch).start;k&&(f.top<b.top-2?(d(f.right,f.top,null,f.bottom),d(l,b.top,b.left,b.bottom)):d(f.right,f.top,b.left-f.right,f.bottom));f.bottom<b.top&&d(l,f.bottom,null,b.top)}c.appendChild(h)}function rd(a){if(a.state.focused){var b=a.display;clearInterval(b.blinker);var c=!0;b.cursorDiv.style.visibility="";0<a.options.cursorBlinkRate?b.blinker=setInterval(function(){return b.cursorDiv.style.visibility=(c=!c)?"":"hidden"},
+a.options.cursorBlinkRate):0>a.options.cursorBlinkRate&&(b.cursorDiv.style.visibility="hidden")}}function Ke(a){a.state.focused||(a.display.input.focus(),sd(a))}function Le(a){a.state.delayingBlurEvent=!0;setTimeout(function(){a.state.delayingBlurEvent&&(a.state.delayingBlurEvent=!1,Db(a))},100)}function sd(a,b){a.state.delayingBlurEvent&&(a.state.delayingBlurEvent=!1);"nocursor"!=a.options.readOnly&&(a.state.focused||(F(a,"focus",a,b),a.state.focused=!0,Ea(a.display.wrapper,"CodeMirror-focused"),
+a.curOp||a.display.selForContextMenu==a.doc.sel||(a.display.input.reset(),R&&setTimeout(function(){return a.display.input.reset(!0)},20)),a.display.input.receivedFocus()),rd(a))}function Db(a,b){a.state.delayingBlurEvent||(a.state.focused&&(F(a,"blur",a,b),a.state.focused=!1,Ra(a.display.wrapper,"CodeMirror-focused")),clearInterval(a.display.blinker),setTimeout(function(){a.state.focused||(a.display.shift=!1)},150))}function sc(a){a=a.display;for(var b=a.lineDiv.offsetTop,c=0;c<a.view.length;c++){var d=
+a.view[c],e=void 0;if(!d.hidden){if(C&&8>B)var f=d.node.offsetTop+d.node.offsetHeight,e=f-b,b=f;else e=d.node.getBoundingClientRect(),e=e.bottom-e.top;f=d.line.height-e;if(2>e&&(e=Oa(a)),(.005<f||-.005>f)&&(la(d.line,e),Me(d.line),d.rest))for(e=0;e<d.rest.length;e++)Me(d.rest[e])}}}function Me(a){if(a.widgets)for(var b=0;b<a.widgets.length;++b)a.widgets[b].height=a.widgets[b].node.parentNode.offsetHeight}function td(a,b,c){var d=c&&null!=c.top?Math.max(0,c.top):a.scroller.scrollTop,d=Math.floor(d-
+a.lineSpace.offsetTop),e=c&&null!=c.bottom?c.bottom:d+a.wrapper.clientHeight,d=Ha(b,d),e=Ha(b,e);if(c&&c.ensure){var f=c.ensure.from.line;c=c.ensure.to.line;f<d?(d=f,e=Ha(b,na(w(b,f))+a.wrapper.clientHeight)):Math.min(c,b.lastLine())>=e&&(d=Ha(b,na(w(b,c))-a.wrapper.clientHeight),e=c)}return{from:d,to:Math.max(e,d+1)}}function Ne(a){var b=a.display,c=b.view;if(b.alignWidgets||b.gutters.firstChild&&a.options.fixedGutter){for(var d=pd(b)-b.scroller.scrollLeft+a.doc.scrollLeft,e=b.gutters.offsetWidth,
+f=d+"px",g=0;g<c.length;g++)if(!c[g].hidden){a.options.fixedGutter&&(c[g].gutter&&(c[g].gutter.style.left=f),c[g].gutterBackground&&(c[g].gutterBackground.style.left=f));var h=c[g].alignable;if(h)for(var k=0;k<h.length;k++)h[k].style.left=f}a.options.fixedGutter&&(b.gutters.style.left=d+e+"px")}}function Oe(a){if(!a.options.lineNumbers)return!1;var b=a.doc,b=Qc(a.options,b.first+b.size-1),c=a.display;if(b.length!=c.lineNumChars){var d=c.measure.appendChild(r("div",[r("div",b)],"CodeMirror-linenumber CodeMirror-gutter-elt")),
+e=d.firstChild.offsetWidth,d=d.offsetWidth-e;return c.lineGutter.style.width="",c.lineNumInnerWidth=Math.max(e,c.lineGutter.offsetWidth-d)+1,c.lineNumWidth=c.lineNumInnerWidth+d,c.lineNumChars=c.lineNumInnerWidth?b.length:-1,c.lineGutter.style.width=c.lineNumWidth+"px",ud(a),!0}return!1}function vd(a,b){var c=a.display,d=Oa(a.display);0>b.top&&(b.top=0);var e=a.curOp&&null!=a.curOp.scrollTop?a.curOp.scrollTop:c.scroller.scrollTop,f=kd(a),g={};b.bottom-b.top>f&&(b.bottom=b.top+f);var h=a.doc.height+
+jd(c),k=b.top<d,d=b.bottom>h-d;b.top<e?g.scrollTop=k?0:b.top:b.bottom>e+f&&(f=Math.min(b.top,(d?h:b.bottom)-f),f!=e&&(g.scrollTop=f));e=a.curOp&&null!=a.curOp.scrollLeft?a.curOp.scrollLeft:c.scroller.scrollLeft;c=Ma(a)-(a.options.fixedGutter?c.gutters.offsetWidth:0);f=b.right-b.left>c;return f&&(b.right=b.left+c),10>b.left?g.scrollLeft=0:b.left<e?g.scrollLeft=Math.max(0,b.left-(f?0:10)):b.right>c+e-3&&(g.scrollLeft=b.right+(f?0:10)-c),g}function tc(a,b){null!=b&&(uc(a),a.curOp.scrollTop=(null==a.curOp.scrollTop?
+a.doc.scrollTop:a.curOp.scrollTop)+b)}function fb(a){uc(a);var b=a.getCursor();a.curOp.scrollToPos={from:b,to:b,margin:a.options.cursorScrollMargin}}function Eb(a,b,c){null==b&&null==c||uc(a);null!=b&&(a.curOp.scrollLeft=b);null!=c&&(a.curOp.scrollTop=c)}function uc(a){var b=a.curOp.scrollToPos;b&&(a.curOp.scrollToPos=null,Pe(a,Ge(a,b.from),Ge(a,b.to),b.margin))}function Pe(a,b,c,d){b=vd(a,{left:Math.min(b.left,c.left),top:Math.min(b.top,c.top)-d,right:Math.max(b.right,c.right),bottom:Math.max(b.bottom,
+c.bottom)+d});Eb(a,b.scrollLeft,b.scrollTop)}function Fb(a,b){2>Math.abs(a.doc.scrollTop-b)||(wa||wd(a,{top:b}),Qe(a,b,!0),wa&&wd(a),Gb(a,100))}function Qe(a,b,c){b=Math.min(a.display.scroller.scrollHeight-a.display.scroller.clientHeight,b);(a.display.scroller.scrollTop!=b||c)&&(a.doc.scrollTop=b,a.display.scrollbars.setScrollTop(b),a.display.scroller.scrollTop!=b&&(a.display.scroller.scrollTop=b))}function Sa(a,b,c,d){b=Math.min(b,a.display.scroller.scrollWidth-a.display.scroller.clientWidth);(c?
+b==a.doc.scrollLeft:2>Math.abs(a.doc.scrollLeft-b))&&!d||(a.doc.scrollLeft=b,Ne(a),a.display.scroller.scrollLeft!=b&&(a.display.scroller.scrollLeft=b),a.display.scrollbars.setScrollLeft(b))}function Hb(a){var b=a.display,c=b.gutters.offsetWidth,d=Math.round(a.doc.height+jd(a.display));return{clientHeight:b.scroller.clientHeight,viewHeight:b.wrapper.clientHeight,scrollWidth:b.scroller.scrollWidth,clientWidth:b.scroller.clientWidth,viewWidth:b.wrapper.clientWidth,barLeft:a.options.fixedGutter?c:0,docHeight:d,
+scrollHeight:d+oa(a)+b.barHeight,nativeBarWidth:b.nativeBarWidth,gutterWidth:c}}function gb(a,b){b||(b=Hb(a));var c=a.display.barWidth,d=a.display.barHeight;Re(a,b);for(var e=0;4>e&&c!=a.display.barWidth||d!=a.display.barHeight;e++)c!=a.display.barWidth&&a.options.lineWrapping&&sc(a),Re(a,Hb(a)),c=a.display.barWidth,d=a.display.barHeight}function Re(a,b){var c=a.display,d=c.scrollbars.update(b);c.sizer.style.paddingRight=(c.barWidth=d.right)+"px";c.sizer.style.paddingBottom=(c.barHeight=d.bottom)+
+"px";c.heightForcer.style.borderBottom=d.bottom+"px solid transparent";d.right&&d.bottom?(c.scrollbarFiller.style.display="block",c.scrollbarFiller.style.height=d.bottom+"px",c.scrollbarFiller.style.width=d.right+"px"):c.scrollbarFiller.style.display="";d.bottom&&a.options.coverGutterNextToScrollbar&&a.options.fixedGutter?(c.gutterFiller.style.display="block",c.gutterFiller.style.height=d.bottom+"px",c.gutterFiller.style.width=b.gutterWidth+"px"):c.gutterFiller.style.display=""}function Se(a){a.display.scrollbars&&
+(a.display.scrollbars.clear(),a.display.scrollbars.addClass&&Ra(a.display.wrapper,a.display.scrollbars.addClass));a.display.scrollbars=new Te[a.options.scrollbarStyle](function(b){a.display.wrapper.insertBefore(b,a.display.scrollbarFiller);t(b,"mousedown",function(){a.state.focused&&setTimeout(function(){return a.display.input.focus()},0)});b.setAttribute("cm-not-content","true")},function(b,c){"horizontal"==c?Sa(a,b):Fb(a,b)},a);a.display.scrollbars.addClass&&Ea(a.display.wrapper,a.display.scrollbars.addClass)}
+function Ta(a){a.curOp={cm:a,viewChanged:!1,startHeight:a.doc.height,forceUpdate:!1,updateInput:null,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++xg};a=a.curOp;eb?eb.ops.push(a):a.ownsGroup=eb={ops:[a],delayedCallbacks:[]}}function Ua(a){sg(a.curOp,function(a){for(var c=0;c<a.ops.length;c++)a.ops[c].cm.curOp=null;a=a.ops;for(c=0;c<a.length;c++){var d=a[c],e=d.cm,f=e.display,
+g=e.display;!g.scrollbarsClipped&&g.scroller.offsetWidth&&(g.nativeBarWidth=g.scroller.offsetWidth-g.scroller.clientWidth,g.heightForcer.style.height=oa(e)+"px",g.sizer.style.marginBottom=-g.nativeBarWidth+"px",g.sizer.style.borderRightWidth=oa(e)+"px",g.scrollbarsClipped=!0);d.updateMaxLine&&Wc(e);d.mustUpdate=d.viewChanged||d.forceUpdate||null!=d.scrollTop||d.scrollToPos&&(d.scrollToPos.from.line<f.viewFrom||d.scrollToPos.to.line>=f.viewTo)||f.maxLineChanged&&e.options.lineWrapping;d.update=d.mustUpdate&&
+new vc(e,d.mustUpdate&&{top:d.scrollTop,ensure:d.scrollToPos},d.forceUpdate)}for(c=0;c<a.length;c++)d=a[c],d.updatedDisplay=d.mustUpdate&&xd(d.cm,d.update);for(c=0;c<a.length;c++)d=a[c],e=d.cm,f=e.display,d.updatedDisplay&&sc(e),d.barMeasure=Hb(e),f.maxLineChanged&&!e.options.lineWrapping&&(g=void 0,g=f.maxLine.text.length,g=ra(e,$a(e,f.maxLine),g,void 0),d.adjustWidthTo=g.left+3,e.display.sizerWidth=d.adjustWidthTo,d.barMeasure.scrollWidth=Math.max(f.scroller.clientWidth,f.sizer.offsetLeft+d.adjustWidthTo+
+oa(e)+e.display.barWidth),d.maxScrollLeft=Math.max(0,f.sizer.offsetLeft+d.adjustWidthTo-Ma(e))),(d.updatedDisplay||d.selectionChanged)&&(d.preparedSelection=f.input.prepareSelection(d.focus));for(c=0;c<a.length;c++)d=a[c],e=d.cm,null!=d.adjustWidthTo&&(e.display.sizer.style.minWidth=d.adjustWidthTo+"px",d.maxScrollLeft<e.doc.scrollLeft&&Sa(e,Math.min(e.display.scroller.scrollLeft,d.maxScrollLeft),!0),e.display.maxLineChanged=!1),f=d.focus&&d.focus==qa()&&(!document.hasFocus||document.hasFocus()),
+d.preparedSelection&&e.display.input.showSelection(d.preparedSelection,f),(d.updatedDisplay||d.startHeight!=e.doc.height)&&gb(e,d.barMeasure),d.updatedDisplay&&yd(e,d.barMeasure),d.selectionChanged&&rd(e),e.state.focused&&d.updateInput&&e.display.input.reset(d.typing),f&&Ke(d.cm);for(c=0;c<a.length;c++){d=a[c];e=d.cm;f=e.display;g=e.doc;if(d.updatedDisplay&&Ue(e,d.update),null==f.wheelStartX||null==d.scrollTop&&null==d.scrollLeft&&!d.scrollToPos||(f.wheelStartX=f.wheelStartY=null),null!=d.scrollTop&&
+Qe(e,d.scrollTop,d.forceScroll),null!=d.scrollLeft&&Sa(e,d.scrollLeft,!0,!0),d.scrollToPos){var h=v(g,d.scrollToPos.from),k=v(g,d.scrollToPos.to),l=d.scrollToPos.margin;null==l&&(l=0);var n=void 0;e.options.lineWrapping||h!=k||(h=h.ch?m(h.line,"before"==h.sticky?h.ch-1:h.ch,"after"):h,k="before"==h.sticky?m(h.line,h.ch+1,"before"):h);for(var q=0;5>q;q++){var p=!1,n=ia(e,h),u=k&&k!=h?ia(e,k):n,n={left:Math.min(n.left,u.left),top:Math.min(n.top,u.top)-l,right:Math.max(n.left,u.left),bottom:Math.max(n.bottom,
+u.bottom)+l},u=vd(e,n),O=e.doc.scrollTop,t=e.doc.scrollLeft;if(null!=u.scrollTop&&(Fb(e,u.scrollTop),1<Math.abs(e.doc.scrollTop-O)&&(p=!0)),null!=u.scrollLeft&&(Sa(e,u.scrollLeft),1<Math.abs(e.doc.scrollLeft-t)&&(p=!0)),!p)break}k=n;K(e,"scrollCursorIntoView")||(l=e.display,q=l.sizer.getBoundingClientRect(),h=null,(0>k.top+q.top?h=!0:k.bottom+q.top>(window.innerHeight||document.documentElement.clientHeight)&&(h=!1),null==h||yg)||(k=r("div","​",null,"position: absolute;\n                         top: "+
+(k.top-l.viewOffset-e.display.lineSpace.offsetTop)+"px;\n                         height: "+(k.bottom-k.top+oa(e)+l.barHeight)+"px;\n                         left: "+k.left+"px; width: "+Math.max(2,k.right-k.left)+"px;"),e.display.lineSpace.appendChild(k),k.scrollIntoView(h),e.display.lineSpace.removeChild(k)))}k=d.maybeHiddenMarkers;h=d.maybeUnhiddenMarkers;if(k)for(l=0;l<k.length;++l)k[l].lines.length||F(k[l],"hide");if(h)for(k=0;k<h.length;++k)h[k].lines.length&&F(h[k],"unhide");f.wrapper.offsetHeight&&
+(g.scrollTop=e.display.scroller.scrollTop);d.changeObjs&&F(e,"changes",e,d.changeObjs);d.update&&d.update.finish()}})}function Y(a,b){if(a.curOp)return b();Ta(a);try{return b()}finally{Ua(a)}}function L(a,b){return function(){if(a.curOp)return b.apply(a,arguments);Ta(a);try{return b.apply(a,arguments)}finally{Ua(a)}}}function T(a){return function(){if(this.curOp)return a.apply(this,arguments);Ta(this);try{return a.apply(this,arguments)}finally{Ua(this)}}}function M(a){return function(){var b=this.cm;
+if(!b||b.curOp)return a.apply(this,arguments);Ta(b);try{return a.apply(this,arguments)}finally{Ua(b)}}}function V(a,b,c,d){null==b&&(b=a.doc.first);null==c&&(c=a.doc.first+a.doc.size);d||(d=0);var e=a.display;if(d&&c<e.viewTo&&(null==e.updateLineNumbers||e.updateLineNumbers>b)&&(e.updateLineNumbers=b),a.curOp.viewChanged=!0,b>=e.viewTo)xa&&Uc(a.doc,b)<e.viewTo&&za(a);else if(c<=e.viewFrom)xa&&ae(a.doc,c+d)>e.viewFrom?za(a):(e.viewFrom+=d,e.viewTo+=d);else if(b<=e.viewFrom&&c>=e.viewTo)za(a);else if(b<=
+e.viewFrom){var f=wc(a,c,c+d,1);f?(e.view=e.view.slice(f.index),e.viewFrom=f.lineN,e.viewTo+=d):za(a)}else if(c>=e.viewTo)(f=wc(a,b,b,-1))?(e.view=e.view.slice(0,f.index),e.viewTo=f.lineN):za(a);else{var f=wc(a,b,b,-1),g=wc(a,c,c+d,1);f&&g?(e.view=e.view.slice(0,f.index).concat(oc(a,f.lineN,g.lineN)).concat(e.view.slice(g.index)),e.viewTo+=d):za(a)}(a=e.externalMeasured)&&(c<a.lineN?a.lineN+=d:b<a.lineN+a.size&&(e.externalMeasured=null))}function Aa(a,b,c){a.curOp.viewChanged=!0;var d=a.display,e=
+a.display.externalMeasured;(e&&b>=e.lineN&&b<e.lineN+e.size&&(d.externalMeasured=null),b<d.viewFrom||b>=d.viewTo)||(a=d.view[Na(a,b)],null!=a.node&&(a=a.changes||(a.changes=[]),-1==N(a,c)&&a.push(c)))}function za(a){a.display.viewFrom=a.display.viewTo=a.doc.first;a.display.view=[];a.display.viewOffset=0}function wc(a,b,c,d){var e=Na(a,b),f=a.display.view;if(!xa||c==a.doc.first+a.doc.size)return{index:e,lineN:c};for(var g=a.display.viewFrom,h=0;h<e;h++)g+=f[h].size;if(g!=b){if(0<d){if(e==f.length-
+1)return null;b=g+f[e].size-b;e++}else b=g-b;c+=b}for(;Uc(a.doc,c)!=c;){if(e==(0>d?0:f.length-1))return null;c+=d*f[e-(0>d?1:0)].size;e+=d}return{index:e,lineN:c}}function Ve(a){a=a.display.view;for(var b=0,c=0;c<a.length;c++){var d=a[c];d.hidden||d.node&&!d.changes||++b}return b}function Gb(a,b){a.doc.highlightFrontier<a.display.viewTo&&a.state.highlight.set(b,Kc(zg,a))}function zg(a){var b=a.doc;if(!(b.highlightFrontier>=a.display.viewTo)){var c=+new Date+a.options.workTime,d=wb(a,b.highlightFrontier),
+e=[];b.iter(d.line,Math.min(b.first+b.size,a.display.viewTo+500),function(f){if(d.line>=a.display.viewFrom){var g=f.styles,h=f.text.length>a.options.maxHighlightLength?La(b.mode,d.state):null,k=he(a,f,d,!0);h&&(d.state=h);f.styles=k.styles;h=f.styleClasses;(k=k.classes)?f.styleClasses=k:h&&(f.styleClasses=null);k=!g||g.length!=f.styles.length||h!=k&&(!h||!k||h.bgClass!=k.bgClass||h.textClass!=k.textClass);for(h=0;!k&&h<g.length;++h)k=g[h]!=f.styles[h];k&&e.push(d.line);f.stateAfter=d.save()}else f.text.length<=
+a.options.maxHighlightLength&&fd(a,f.text,d),f.stateAfter=0==d.line%5?d.save():null;d.nextLine();if(+new Date>c)return Gb(a,a.options.workDelay),!0});b.highlightFrontier=d.line;b.modeFrontier=Math.max(b.modeFrontier,d.line);e.length&&Y(a,function(){for(var b=0;b<e.length;b++)Aa(a,e[b],"text")})}}function xd(a,b){var c=a.display,d=a.doc;if(b.editorIsHidden)return za(a),!1;if(!b.force&&b.visible.from>=c.viewFrom&&b.visible.to<=c.viewTo&&(null==c.updateLineNumbers||c.updateLineNumbers>=c.viewTo)&&c.renderedView==
+c.view&&0==Ve(a))return!1;Oe(a)&&(za(a),b.dims=md(a));var e=d.first+d.size,f=Math.max(b.visible.from-a.options.viewportMargin,d.first),g=Math.min(e,b.visible.to+a.options.viewportMargin);c.viewFrom<f&&20>f-c.viewFrom&&(f=Math.max(d.first,c.viewFrom));c.viewTo>g&&20>c.viewTo-g&&(g=Math.min(e,c.viewTo));xa&&(f=Uc(a.doc,f),g=ae(a.doc,g));d=f!=c.viewFrom||g!=c.viewTo||c.lastWrapHeight!=b.wrapperHeight||c.lastWrapWidth!=b.wrapperWidth;e=a.display;0==e.view.length||f>=e.viewTo||g<=e.viewFrom?(e.view=oc(a,
+f,g),e.viewFrom=f):(e.viewFrom>f?e.view=oc(a,f,e.viewFrom).concat(e.view):e.viewFrom<f&&(e.view=e.view.slice(Na(a,f))),e.viewFrom=f,e.viewTo<g?e.view=e.view.concat(oc(a,e.viewTo,g)):e.viewTo>g&&(e.view=e.view.slice(0,Na(a,g))));e.viewTo=g;c.viewOffset=na(w(a.doc,c.viewFrom));a.display.mover.style.top=c.viewOffset+"px";g=Ve(a);if(!d&&0==g&&!b.force&&c.renderedView==c.view&&(null==c.updateLineNumbers||c.updateLineNumbers>=c.viewTo))return!1;a.hasFocus()?f=null:(f=qa())&&va(a.display.lineDiv,f)?(f={activeElt:f},
+window.getSelection&&(e=window.getSelection(),e.anchorNode&&e.extend&&va(a.display.lineDiv,e.anchorNode)&&(f.anchorNode=e.anchorNode,f.anchorOffset=e.anchorOffset,f.focusNode=e.focusNode,f.focusOffset=e.focusOffset))):f=null;4<g&&(c.lineDiv.style.display="none");Ag(a,c.updateLineNumbers,b.dims);4<g&&(c.lineDiv.style.display="");c.renderedView=c.view;(g=f)&&g.activeElt&&g.activeElt!=qa()&&(g.activeElt.focus(),g.anchorNode&&va(document.body,g.anchorNode)&&va(document.body,g.focusNode))&&(f=window.getSelection(),
+e=document.createRange(),e.setEnd(g.anchorNode,g.anchorOffset),e.collapse(!1),f.removeAllRanges(),f.addRange(e),f.extend(g.focusNode,g.focusOffset));return X(c.cursorDiv),X(c.selectionDiv),c.gutters.style.height=c.sizer.style.minHeight=0,d&&(c.lastWrapHeight=b.wrapperHeight,c.lastWrapWidth=b.wrapperWidth,Gb(a,400)),c.updateLineNumbers=null,!0}function Ue(a,b){for(var c=b.viewport,d=!0;(d&&a.options.lineWrapping&&b.oldDisplayWidth!=Ma(a)||(c&&null!=c.top&&(c={top:Math.min(a.doc.height+jd(a.display)-
+kd(a),c.top)}),b.visible=td(a.display,a.doc,c),!(b.visible.from>=a.display.viewFrom&&b.visible.to<=a.display.viewTo)))&&xd(a,b);d=!1)sc(a),d=Hb(a),Cb(a),gb(a,d),yd(a,d),b.force=!1;b.signal(a,"update",a);a.display.viewFrom==a.display.reportedViewFrom&&a.display.viewTo==a.display.reportedViewTo||(b.signal(a,"viewportChange",a,a.display.viewFrom,a.display.viewTo),a.display.reportedViewFrom=a.display.viewFrom,a.display.reportedViewTo=a.display.viewTo)}function wd(a,b){var c=new vc(a,b);if(xd(a,c)){sc(a);
+Ue(a,c);var d=Hb(a);Cb(a);gb(a,d);yd(a,d);c.finish()}}function Ag(a,b,c){function d(b){var d=b.nextSibling;return R&&ha&&a.display.currentWheelTarget==b?b.style.display="none":b.parentNode.removeChild(b),d}for(var e=a.display,f=a.options.lineNumbers,g=e.lineDiv,h=g.firstChild,k=e.view,e=e.viewFrom,l=0;l<k.length;l++){var n=k[l];if(!n.hidden)if(n.node&&n.node.parentNode==g){for(;h!=n.node;)h=d(h);h=f&&null!=b&&b<=e&&n.lineNumber;n.changes&&(-1<N(n.changes,"gutter")&&(h=!1),se(a,n,e,c));h&&(X(n.lineNumber),
+n.lineNumber.appendChild(document.createTextNode(Qc(a.options,e))));h=n.node.nextSibling}else{var q=ug(a,n,e,c);g.insertBefore(q,h)}e+=n.size}for(;h;)h=d(h)}function ud(a){a.display.sizer.style.marginLeft=a.display.gutters.offsetWidth+"px"}function yd(a,b){a.display.sizer.style.minHeight=b.docHeight+"px";a.display.heightForcer.style.top=b.docHeight+"px";a.display.gutters.style.height=b.docHeight+a.display.barHeight+oa(a)+"px"}function We(a){var b=a.display.gutters,c=a.options.gutters;X(b);for(var d=
+0;d<c.length;++d){var e=c[d],f=b.appendChild(r("div",null,"CodeMirror-gutter "+e));"CodeMirror-linenumbers"==e&&(a.display.lineGutter=f,f.style.width=(a.display.lineNumWidth||1)+"px")}b.style.display=d?"":"none";ud(a)}function zd(a){var b=N(a.gutters,"CodeMirror-linenumbers");-1==b&&a.lineNumbers?a.gutters=a.gutters.concat(["CodeMirror-linenumbers"]):-1<b&&!a.lineNumbers&&(a.gutters=a.gutters.slice(0),a.gutters.splice(b,1))}function Xe(a){var b=a.wheelDeltaX,c=a.wheelDeltaY;return null==b&&a.detail&&
+a.axis==a.HORIZONTAL_AXIS&&(b=a.detail),null==c&&a.detail&&a.axis==a.VERTICAL_AXIS?c=a.detail:null==c&&(c=a.wheelDelta),{x:b,y:c}}function Bg(a){a=Xe(a);return a.x*=ba,a.y*=ba,a}function Ye(a,b){var c=Xe(b),d=c.x,c=c.y,e=a.display,f=e.scroller,g=f.scrollWidth>f.clientWidth,h=f.scrollHeight>f.clientHeight;if(d&&g||c&&h){if(c&&ha&&R){var g=b.target,k=e.view;a:for(;g!=f;g=g.parentNode)for(var l=0;l<k.length;l++)if(k[l].node==g){a.display.currentWheelTarget=g;break a}}if(d&&!wa&&!ja&&null!=ba)return c&&
+h&&Fb(a,Math.max(0,f.scrollTop+c*ba)),Sa(a,Math.max(0,f.scrollLeft+d*ba)),(!c||c&&h)&&S(b),void(e.wheelStartX=null);c&&null!=ba&&(h=c*ba,g=a.doc.scrollTop,k=g+e.wrapper.clientHeight,0>h?g=Math.max(0,g+h-50):k=Math.min(a.doc.height,k+h+50),wd(a,{top:g,bottom:k}));20>xc&&(null==e.wheelStartX?(e.wheelStartX=f.scrollLeft,e.wheelStartY=f.scrollTop,e.wheelDX=d,e.wheelDY=c,setTimeout(function(){if(null!=e.wheelStartX){var a=f.scrollLeft-e.wheelStartX,b=f.scrollTop-e.wheelStartY,a=b&&e.wheelDY&&b/e.wheelDY||
+a&&e.wheelDX&&a/e.wheelDX;e.wheelStartX=e.wheelStartY=null;a&&(ba=(ba*xc+a)/(xc+1),++xc)}},200)):(e.wheelDX+=d,e.wheelDY+=c))}}function ka(a,b){var c=a[b];a.sort(function(a,b){return x(a.from(),b.from())});b=N(a,c);for(c=1;c<a.length;c++){var d=a[c],e=a[c-1];if(0<=x(e.to(),d.from())){var f=ic(e.from(),d.from()),g=hc(e.to(),d.to()),d=e.empty()?d.from()==d.head:e.from()==e.head;c<=b&&--b;a.splice(--c,2,new A(d?g:f,d?f:g))}}return new ca(a,b)}function ua(a,b){return new ca([new A(a,b||a)],0)}function Ba(a){return a.text?
+m(a.from.line+a.text.length-1,z(a.text).length+(1==a.text.length?a.from.ch:0)):a.to}function Ze(a,b){if(0>x(a,b.from))return a;if(0>=x(a,b.to))return Ba(b);var c=a.line+b.text.length-(b.to.line-b.from.line)-1,d=a.ch;return a.line==b.to.line&&(d+=Ba(b).ch-b.to.ch),m(c,d)}function Ad(a,b){for(var c=[],d=0;d<a.sel.ranges.length;d++){var e=a.sel.ranges[d];c.push(new A(Ze(e.anchor,b),Ze(e.head,b)))}return ka(c,a.sel.primIndex)}function $e(a,b,c){return a.line==b.line?m(c.line,a.ch-b.ch+c.ch):m(c.line+
+(a.line-b.line),a.ch)}function Bd(a){a.doc.mode=dd(a.options,a.doc.modeOption);Ib(a)}function Ib(a){a.doc.iter(function(a){a.stateAfter&&(a.stateAfter=null);a.styles&&(a.styles=null)});a.doc.modeFrontier=a.doc.highlightFrontier=a.doc.first;Gb(a,100);a.state.modeGen++;a.curOp&&V(a)}function af(a,b){return 0==b.from.ch&&0==b.to.ch&&""==z(b.text)&&(!a.cm||a.cm.options.wholeLineUpdateBefore)}function Cd(a,b,c,d){function e(a,c,e){a.text=c;a.stateAfter&&(a.stateAfter=null);a.styles&&(a.styles=null);null!=
+a.order&&(a.order=null);Xd(a);Yd(a,e);c=d?d(a):1;c!=a.height&&la(a,c);P(a,"change",a,b)}function f(a,b){for(var e=[],f=a;f<b;++f)e.push(new hb(k[f],c?c[f]:null,d));return e}var g=b.from,h=b.to,k=b.text,l=w(a,g.line),n=w(a,h.line),q=z(k),p=c?c[k.length-1]:null,u=h.line-g.line;b.full?(a.insert(0,f(0,k.length)),a.remove(k.length,a.size-k.length)):af(a,b)?(h=f(0,k.length-1),e(n,n.text,p),u&&a.remove(g.line,u),h.length&&a.insert(g.line,h)):l==n?1==k.length?e(l,l.text.slice(0,g.ch)+q+l.text.slice(h.ch),
+p):(u=f(1,k.length-1),u.push(new hb(q+l.text.slice(h.ch),p,d)),e(l,l.text.slice(0,g.ch)+k[0],c?c[0]:null),a.insert(g.line+1,u)):1==k.length?(e(l,l.text.slice(0,g.ch)+k[0]+n.text.slice(h.ch),c?c[0]:null),a.remove(g.line+1,u)):(e(l,l.text.slice(0,g.ch)+k[0],c?c[0]:null),e(n,q+n.text.slice(h.ch),p),p=f(1,k.length-1),1<u&&a.remove(g.line+1,u-1),a.insert(g.line+1,p));P(a,"change",a,b)}function Va(a,b,c){function d(a,f,g){if(a.linked)for(var h=0;h<a.linked.length;++h){var k=a.linked[h];if(k.doc!=f){var l=
+g&&k.sharedHist;c&&!l||(b(k.doc,l),d(k.doc,a,l))}}}d(a,null,!0)}function bf(a,b){if(b.cm)throw Error("This document is already in use.");a.doc=b;b.cm=a;qd(a);Bd(a);cf(a);a.options.lineWrapping||Wc(a);a.options.mode=b.modeOption;V(a)}function cf(a){("rtl"==a.doc.direction?Ea:Ra)(a.display.lineDiv,"CodeMirror-rtl")}function Cg(a){Y(a,function(){cf(a);V(a)})}function yc(a){this.done=[];this.undone=[];this.undoDepth=1/0;this.lastModTime=this.lastSelTime=0;this.lastOrigin=this.lastSelOrigin=this.lastOp=
+this.lastSelOp=null;this.generation=this.maxGeneration=a||1}function Dd(a,b){var c={from:Sc(b.from),to:Ba(b),text:Ga(a,b.from,b.to)};return df(a,c,b.from.line,b.to.line+1),Va(a,function(a){return df(a,c,b.from.line,b.to.line+1)},!0),c}function ef(a){for(;a.length&&z(a).ranges;)a.pop()}function ff(a,b,c,d){var e=a.history;e.undone.length=0;var f,g,h=+new Date,k;if(k=e.lastOp==d||e.lastOrigin==b.origin&&b.origin&&("+"==b.origin.charAt(0)&&a.cm&&e.lastModTime>h-a.cm.options.historyEventDelay||"*"==b.origin.charAt(0)))k=
+f=e.lastOp==d?(ef(e.done),z(e.done)):e.done.length&&!z(e.done).ranges?z(e.done):1<e.done.length&&!e.done[e.done.length-2].ranges?(e.done.pop(),z(e.done)):void 0;if(k)g=z(f.changes),0==x(b.from,b.to)&&0==x(b.from,g.to)?g.to=Ba(b):f.changes.push(Dd(a,b));else for((f=z(e.done))&&f.ranges||zc(a.sel,e.done),f={changes:[Dd(a,b)],generation:e.generation},e.done.push(f);e.done.length>e.undoDepth;)e.done.shift(),e.done[0].ranges||e.done.shift();e.done.push(c);e.generation=++e.maxGeneration;e.lastModTime=e.lastSelTime=
+h;e.lastOp=e.lastSelOp=d;e.lastOrigin=e.lastSelOrigin=b.origin;g||F(a,"historyAdded")}function zc(a,b){var c=z(b);c&&c.ranges&&c.equals(a)||b.push(a)}function df(a,b,c,d){var e=b["spans_"+a.id],f=0;a.iter(Math.max(a.first,c),Math.min(a.first+a.size,d),function(d){d.markedSpans&&((e||(e=b["spans_"+a.id]={}))[f]=d.markedSpans);++f})}function Dg(a){if(!a)return null;for(var b,c=0;c<a.length;++c)a[c].marker.explicitlyCleared?b||(b=a.slice(0,c)):b&&b.push(a[c]);return b?b.length?b:null:a}function gf(a,
+b){var c;if(c=b["spans_"+a.id]){for(var d=[],e=0;e<b.text.length;++e)d.push(Dg(c[e]));c=d}else c=null;d=Tc(a,b);if(!c)return d;if(!d)return c;for(e=0;e<c.length;++e){var f=c[e],g=d[e];if(f&&g){var h=0;a:for(;h<g.length;++h){for(var k=g[h],l=0;l<f.length;++l)if(f[l].marker==k.marker)continue a;f.push(k)}}else g&&(c[e]=g)}return c}function ib(a,b,c){for(var d=[],e=0;e<a.length;++e){var f=a[e];if(f.ranges)d.push(c?ca.prototype.deepCopy.call(f):f);else{var f=f.changes,g=[];d.push({changes:g});for(var h=
+0;h<f.length;++h){var k=f[h],l=void 0;if(g.push({from:k.from,to:k.to,text:k.text}),b)for(var n in k)(l=n.match(/^spans_(\d+)$/))&&-1<N(b,Number(l[1]))&&(z(g)[n]=k[n],delete k[n])}}}return d}function Ed(a,b,c,d){return d?(a=a.anchor,c&&(d=0>x(b,a),d!=0>x(c,a)?(a=b,b=c):d!=0>x(b,c)&&(b=c)),new A(a,b)):new A(c||b,b)}function Ac(a,b,c,d,e){null==e&&(e=a.cm&&(a.cm.display.shift||a.extend));Q(a,new ca([Ed(a.sel.primary(),b,c,e)],0),d)}function hf(a,b,c){for(var d=[],e=a.cm&&(a.cm.display.shift||a.extend),
+f=0;f<a.sel.ranges.length;f++)d[f]=Ed(a.sel.ranges[f],b[f],null,e);Q(a,ka(d,a.sel.primIndex),c)}function Fd(a,b,c,d){var e=a.sel.ranges.slice(0);e[b]=c;Q(a,ka(e,a.sel.primIndex),d)}function Eg(a,b,c){c={ranges:b.ranges,update:function(b){this.ranges=[];for(var c=0;c<b.length;c++)this.ranges[c]=new A(v(a,b[c].anchor),v(a,b[c].head))},origin:c&&c.origin};return F(a,"beforeSelectionChange",a,c),a.cm&&F(a.cm,"beforeSelectionChange",a.cm,c),c.ranges!=b.ranges?ka(c.ranges,c.ranges.length-1):b}function jf(a,
+b,c){var d=a.history.done,e=z(d);e&&e.ranges?(d[d.length-1]=b,Bc(a,b,c)):Q(a,b,c)}function Q(a,b,c){Bc(a,b,c);b=a.sel;var d=a.cm?a.cm.curOp.id:NaN,e=a.history,f=c&&c.origin,g;if(!(g=d==e.lastSelOp)&&(g=f&&e.lastSelOrigin==f)&&!(g=e.lastModTime==e.lastSelTime&&e.lastOrigin==f)){g=z(e.done);var h=f.charAt(0);g="*"==h||"+"==h&&g.ranges.length==b.ranges.length&&g.somethingSelected()==b.somethingSelected()&&new Date-a.history.lastSelTime<=(a.cm?a.cm.options.historyEventDelay:500)}g?e.done[e.done.length-
+1]=b:zc(b,e.done);e.lastSelTime=+new Date;e.lastSelOrigin=f;e.lastSelOp=d;c&&!1!==c.clearRedo&&ef(e.undone)}function Bc(a,b,c){(fa(a,"beforeSelectionChange")||a.cm&&fa(a.cm,"beforeSelectionChange"))&&(b=Eg(a,b,c));kf(a,lf(a,b,c&&c.bias||(0>x(b.primary().head,a.sel.primary().head)?-1:1),!0));c&&!1===c.scroll||!a.cm||fb(a.cm)}function kf(a,b){b.equals(a.sel)||(a.sel=b,a.cm&&(a.cm.curOp.updateInput=a.cm.curOp.selectionChanged=!0,de(a.cm)),P(a,"cursorActivity",a))}function mf(a){kf(a,lf(a,a.sel,null,
+!1))}function lf(a,b,c,d){for(var e,f=0;f<b.ranges.length;f++){var g=b.ranges[f],h=b.ranges.length==a.sel.ranges.length&&a.sel.ranges[f],k=Gd(a,g.anchor,h&&h.anchor,c,d),h=Gd(a,g.head,h&&h.head,c,d);(e||k!=g.anchor||h!=g.head)&&(e||(e=b.ranges.slice(0,f)),e[f]=new A(k,h))}return e?ka(e,b.primIndex):b}function jb(a,b,c,d,e){var f=w(a,b.line);if(f.markedSpans)for(var g=0;g<f.markedSpans.length;++g){var h=f.markedSpans[g],k=h.marker;if((null==h.from||(k.inclusiveLeft?h.from<=b.ch:h.from<b.ch))&&(null==
+h.to||(k.inclusiveRight?h.to>=b.ch:h.to>b.ch))){if(e&&(F(k,"beforeCursorEnter"),k.explicitlyCleared)){if(f.markedSpans){--g;continue}break}if(k.atomic){if(c&&(g=k.find(0>d?1:-1),h=void 0,(0>d?k.inclusiveRight:k.inclusiveLeft)&&(g=nf(a,g,-d,g&&g.line==b.line?f:null)),g&&g.line==b.line&&(h=x(g,c))&&(0>d?0>h:0<h)))return jb(a,g,b,d,e);c=k.find(0>d?-1:1);return(0>d?k.inclusiveLeft:k.inclusiveRight)&&(c=nf(a,c,d,c.line==b.line?f:null)),c?jb(a,c,b,d,e):null}}}return b}function Gd(a,b,c,d,e){d=d||1;return jb(a,
+b,c,d,e)||!e&&jb(a,b,c,d,!0)||jb(a,b,c,-d,e)||!e&&jb(a,b,c,-d,!0)||(a.cantEdit=!0,m(a.first,0))}function nf(a,b,c,d){return 0>c&&0==b.ch?b.line>a.first?v(a,m(b.line-1)):null:0<c&&b.ch==(d||w(a,b.line)).text.length?b.line<a.first+a.size-1?m(b.line+1,0):null:new m(b.line,b.ch+c)}function of(a){a.setSelection(m(a.firstLine(),0),m(a.lastLine()),pa)}function pf(a,b,c){var d={canceled:!1,from:b.from,to:b.to,text:b.text,origin:b.origin,cancel:function(){return d.canceled=!0}};return c&&(d.update=function(b,
+c,g,h){b&&(d.from=v(a,b));c&&(d.to=v(a,c));g&&(d.text=g);void 0!==h&&(d.origin=h)}),F(a,"beforeChange",a,d),a.cm&&F(a.cm,"beforeChange",a.cm,d),d.canceled?null:{from:d.from,to:d.to,text:d.text,origin:d.origin}}function kb(a,b,c){if(a.cm){if(!a.cm.curOp)return L(a.cm,kb)(a,b,c);if(a.cm.state.suppressEdits)return}if(!(fa(a,"beforeChange")||a.cm&&fa(a.cm,"beforeChange"))||(b=pf(a,b,!0)))if(c=qf&&!c&&fg(a,b.from,b.to))for(var d=c.length-1;0<=d;--d)rf(a,{from:c[d].from,to:c[d].to,text:d?[""]:b.text});
+else rf(a,b)}function rf(a,b){if(1!=b.text.length||""!=b.text[0]||0!=x(b.from,b.to)){var c=Ad(a,b);ff(a,b,c,a.cm?a.cm.curOp.id:NaN);Jb(a,b,c,Tc(a,b));var d=[];Va(a,function(a,c){c||-1!=N(d,a.history)||(sf(a.history,b),d.push(a.history));Jb(a,b,null,Tc(a,b))})}}function Cc(a,b,c){if(!a.cm||!a.cm.state.suppressEdits||c){for(var d,e=a.history,f=a.sel,g="undo"==b?e.done:e.undone,h="undo"==b?e.undone:e.done,k=0;k<g.length&&(d=g[k],c?!d.ranges||d.equals(a.sel):d.ranges);k++);if(k!=g.length){for(e.lastOrigin=
+e.lastSelOrigin=null;d=g.pop(),d.ranges;){if(zc(d,h),c&&!d.equals(a.sel))return void Q(a,d,{clearRedo:!1});f=d}var l=[];zc(f,h);h.push({changes:l,generation:e.generation});e.generation=d.generation||++e.maxGeneration;var n=fa(a,"beforeChange")||a.cm&&fa(a.cm,"beforeChange");for(c=d.changes.length-1;0<=c;--c)if(e=function(c){var e=d.changes[c];if(e.origin=b,n&&!pf(a,e,!1))return g.length=0,{};l.push(Dd(a,e));var f=c?Ad(a,e):z(g);Jb(a,e,f,gf(a,e));!c&&a.cm&&a.cm.scrollIntoView({from:e.from,to:Ba(e)});
+var h=[];Va(a,function(a,b){b||-1!=N(h,a.history)||(sf(a.history,e),h.push(a.history));Jb(a,e,null,gf(a,e))})}(c))return e.v}}}function tf(a,b){if(0!=b&&(a.first+=b,a.sel=new ca(ec(a.sel.ranges,function(a){return new A(m(a.anchor.line+b,a.anchor.ch),m(a.head.line+b,a.head.ch))}),a.sel.primIndex),a.cm)){V(a.cm,a.first,a.first-b,b);for(var c=a.cm.display,d=c.viewFrom;d<c.viewTo;d++)Aa(a.cm,d,"gutter")}}function Jb(a,b,c,d){if(a.cm&&!a.cm.curOp)return L(a.cm,Jb)(a,b,c,d);if(b.to.line<a.first)return void tf(a,
+b.text.length-1-(b.to.line-b.from.line));if(!(b.from.line>a.lastLine())){if(b.from.line<a.first){var e=b.text.length-1-(a.first-b.from.line);tf(a,e);b={from:m(a.first,0),to:m(b.to.line+e,b.to.ch),text:[z(b.text)],origin:b.origin}}e=a.lastLine();b.to.line>e&&(b={from:b.from,to:m(e,w(a,e).text.length),text:[b.text[0]],origin:b.origin});b.removed=Ga(a,b.from,b.to);c||(c=Ad(a,b));a.cm?Fg(a.cm,b,d):Cd(a,b,d);Bc(a,c,pa)}}function Fg(a,b,c){var d=a.doc,e=a.display,f=b.from,g=b.to,h=!1,k=f.line;a.options.lineWrapping||
+(k=D(ma(w(d,f.line))),d.iter(k,g.line+1,function(a){if(a==e.maxLine)return h=!0,!0}));-1<d.sel.contains(b.from,b.to)&&de(a);Cd(d,b,c,He(a));a.options.lineWrapping||(d.iter(k,f.line+b.text.length,function(a){var b=kc(a);b>e.maxLineLength&&(e.maxLine=a,e.maxLineLength=b,e.maxLineChanged=!0,h=!1)}),h&&(a.curOp.updateMaxLine=!0));mg(d,f.line);Gb(a,400);c=b.text.length-(g.line-f.line)-1;b.full?V(a):f.line!=g.line||1!=b.text.length||af(a.doc,b)?V(a,f.line,g.line+1,c):Aa(a,f.line,"text");c=fa(a,"changes");
+if((d=fa(a,"change"))||c)b={from:f,to:g,text:b.text,removed:b.removed,origin:b.origin},d&&P(a,"change",a,b),c&&(a.curOp.changeObjs||(a.curOp.changeObjs=[])).push(b);a.display.selForContextMenu=null}function lb(a,b,c,d,e){if(d||(d=c),0>x(d,c)){var f=d;d=c;c=f}"string"==typeof b&&(b=a.splitLines(b));kb(a,{from:c,to:d,text:b,origin:e})}function uf(a,b,c,d){for(var e=0;e<a.length;++e){var f=a[e],g=!0;if(f.ranges)for(f.copied||(f=a[e]=f.deepCopy(),f.copied=!0),g=0;g<f.ranges.length;g++){var h=f.ranges[g].anchor,
+k=b;c<h.line?h.line+=d:k<h.line&&(h.line=k,h.ch=0);h=f.ranges[g].head;k=b;c<h.line?h.line+=d:k<h.line&&(h.line=k,h.ch=0)}else{for(h=0;h<f.changes.length;++h)if(k=f.changes[h],c<k.from.line)k.from=m(k.from.line+d,k.from.ch),k.to=m(k.to.line+d,k.to.ch);else if(b<=k.to.line){g=!1;break}g||(a.splice(0,e+1),e=0)}}}function sf(a,b){var c=b.from.line,d=b.to.line,e=b.text.length-(d-c)-1;uf(a.done,c,d,e);uf(a.undone,c,d,e)}function Kb(a,b,c,d){var e=b,f=b;return"number"==typeof b?f=w(a,Math.max(a.first,Math.min(b,
+a.first+a.size-1))):e=D(b),null==e?null:(d(f,e)&&a.cm&&Aa(a.cm,e,c),f)}function Lb(a){this.lines=a;this.parent=null;for(var b=0,c=0;c<a.length;++c)a[c].parent=this,b+=a[c].height;this.height=b}function Mb(a){this.children=a;for(var b=0,c=0,d=0;d<a.length;++d){var e=a[d],b=b+e.chunkSize(),c=c+e.height;e.parent=this}this.size=b;this.height=c;this.parent=null}function Gg(a,b,c,d){var e=new Nb(a,c,d),f=a.cm;return f&&e.noHScroll&&(f.display.alignWidgets=!0),Kb(a,b,"widget",function(b){var c=b.widgets||
+(b.widgets=[]);if(null==e.insertAt?c.push(e):c.splice(Math.min(c.length-1,Math.max(0,e.insertAt)),0,e),e.line=b,f&&!Ja(a,b))c=na(b)<a.scrollTop,la(b,b.height+zb(e)),c&&tc(f,e.height),f.curOp.forceUpdate=!0;return!0}),P(f,"lineWidgetAdded",f,e,"number"==typeof b?b:D(b)),e}function mb(a,b,c,d,e){if(d&&d.shared)return Hg(a,b,c,d,e);if(a.cm&&!a.cm.curOp)return L(a.cm,mb)(a,b,c,d,e);var f=new Ca(a,e);e=x(b,c);if(d&&Fa(d,f,!1),0<e||0==e&&!1!==f.clearWhenEmpty)return f;if(f.replacedWith&&(f.collapsed=!0,
+f.widgetNode=Za("span",[f.replacedWith],"CodeMirror-widget"),d.handleMouseEvents||f.widgetNode.setAttribute("cm-ignore-events","true"),d.insertLeft&&(f.widgetNode.insertLeft=!0)),f.collapsed){if($d(a,b.line,b,c,f)||b.line!=c.line&&$d(a,c.line,b,c,f))throw Error("Inserting collapsed marker partially overlapping an existing one");xa=!0}f.addToHistory&&ff(a,{from:b,to:c,origin:"markText"},a.sel,NaN);var g,h=b.line,k=a.cm;a.iter(h,c.line+1,function(a){k&&f.collapsed&&!k.options.lineWrapping&&ma(a)==k.display.maxLine&&
+(g=!0);f.collapsed&&h!=b.line&&la(a,0);var d=new jc(f,h==b.line?b.ch:null,h==c.line?c.ch:null);a.markedSpans=a.markedSpans?a.markedSpans.concat([d]):[d];d.marker.attachLine(a);++h});f.collapsed&&a.iter(b.line,c.line+1,function(b){Ja(a,b)&&la(b,0)});f.clearOnEnter&&t(f,"beforeCursorEnter",function(){return f.clear()});f.readOnly&&(qf=!0,(a.history.done.length||a.history.undone.length)&&a.clearHistory());if(f.collapsed&&(f.id=++vf,f.atomic=!0),k){if(g&&(k.curOp.updateMaxLine=!0),f.collapsed)V(k,b.line,
+c.line+1);else if(f.className||f.title||f.startStyle||f.endStyle||f.css)for(d=b.line;d<=c.line;d++)Aa(k,d,"text");f.atomic&&mf(k.doc);P(k,"markerAdded",k,f)}return f}function Hg(a,b,c,d,e){d=Fa(d);d.shared=!1;var f=[mb(a,b,c,d,e)],g=f[0],h=d.widgetNode;return Va(a,function(a){h&&(d.widgetNode=h.cloneNode(!0));f.push(mb(a,v(a,b),v(a,c),d,e));for(var l=0;l<a.linked.length;++l)if(a.linked[l].isParent)return;g=z(f)}),new Ob(f,g)}function wf(a){return a.findMarks(m(a.first,0),a.clipPos(m(a.lastLine())),
+function(a){return a.parent})}function Ig(a){for(var b=0;b<a.length;b++)!function(b){b=a[b];var d=[b.primary.doc];Va(b.primary.doc,function(a){return d.push(a)});for(var e=0;e<b.markers.length;e++){var f=b.markers[e];-1==N(d,f.doc)&&(f.parent=null,b.markers.splice(e--,1))}}(b)}function Jg(a){var b=this;if(xf(b),!K(b,a)&&!ta(b.display,a)){S(a);C&&(yf=+new Date);var c=Qa(b,a,!0),d=a.dataTransfer.files;if(c&&!b.isReadOnly())if(d&&d.length&&window.FileReader&&window.File)for(var e=d.length,f=Array(e),
+g=0,h=0;h<e;++h)!function(a,d){if(!b.options.allowDropFileTypes||-1!=N(b.options.allowDropFileTypes,a.type)){var h=new FileReader;h.onload=L(b,function(){var a=h.result;if(/[\x00-\x08\x0e-\x1f]{2}/.test(a)&&(a=""),f[d]=a,++g==e)c=v(b.doc,c),a={from:c,to:c,text:b.doc.splitLines(f.join(b.doc.lineSeparator())),origin:"paste"},kb(b.doc,a),jf(b.doc,ua(c,Ba(a)))});h.readAsText(a)}}(d[h],h);else{if(b.state.draggingText&&-1<b.doc.sel.contains(c))return b.state.draggingText(a),void setTimeout(function(){return b.display.input.focus()},
+20);try{if(h=a.dataTransfer.getData("Text")){var k;if(b.state.draggingText&&!b.state.draggingText.copy&&(k=b.listSelections()),Bc(b.doc,ua(c,c)),k)for(d=0;d<k.length;++d)lb(b.doc,"",k[d].anchor,k[d].head,"drag");b.replaceSelection(h,"around","paste");b.display.input.focus()}}catch(l){}}}}function xf(a){a.display.dragCursor&&(a.display.lineSpace.removeChild(a.display.dragCursor),a.display.dragCursor=null)}function zf(a){if(document.getElementsByClassName)for(var b=document.getElementsByClassName("CodeMirror"),
+c=0;c<b.length;c++){var d=b[c].CodeMirror;d&&a(d)}}function Kg(){var a;t(window,"resize",function(){null==a&&(a=setTimeout(function(){a=null;zf(Lg)},100))});t(window,"blur",function(){return zf(Db)})}function Lg(a){var b=a.display;b.lastWrapHeight==b.wrapper.clientHeight&&b.lastWrapWidth==b.wrapper.clientWidth||(b.cachedCharWidth=b.cachedTextHeight=b.cachedPaddingH=null,b.scrollbarsClipped=!1,a.setSize())}function Mg(a){var b=a.split(/-(?!$)/);a=b[b.length-1];for(var c,d,e,f,g=0;g<b.length-1;g++){var h=
+b[g];if(/^(cmd|meta|m)$/i.test(h))f=!0;else if(/^a(lt)?$/i.test(h))c=!0;else if(/^(c|ctrl|control)$/i.test(h))d=!0;else{if(!/^s(hift)?$/i.test(h))throw Error("Unrecognized modifier name: "+h);e=!0}}return c&&(a="Alt-"+a),d&&(a="Ctrl-"+a),f&&(a="Cmd-"+a),e&&(a="Shift-"+a),a}function Ng(a){var b={},c;for(c in a)if(a.hasOwnProperty(c)){var d=a[c];if(!/^(name|fallthrough|(de|at)tach)$/.test(c)){if("..."!=d)for(var e=ec(c.split(" "),Mg),f=0;f<e.length;f++){var g=void 0,h=void 0;f==e.length-1?(h=e.join(" "),
+g=d):(h=e.slice(0,f+1).join(" "),g="...");var k=b[h];if(k){if(k!=g)throw Error("Inconsistent bindings for "+h);}else b[h]=g}delete a[c]}}for(var l in b)a[l]=b[l];return a}function nb(a,b,c,d){b=Dc(b);var e=b.call?b.call(a,d):b[a];if(!1===e)return"nothing";if("..."===e)return"multi";if(null!=e&&c(e))return"handled";if(b.fallthrough){if("[object Array]"!=Object.prototype.toString.call(b.fallthrough))return nb(a,b.fallthrough,c,d);for(e=0;e<b.fallthrough.length;e++){var f=nb(a,b.fallthrough[e],c,d);
+if(f)return f}}}function Af(a){a="string"==typeof a?a:Da[a.keyCode];return"Ctrl"==a||"Alt"==a||"Shift"==a||"Mod"==a}function Bf(a,b,c){var d=a;return b.altKey&&"Alt"!=d&&(a="Alt-"+a),(Cf?b.metaKey:b.ctrlKey)&&"Ctrl"!=d&&(a="Ctrl-"+a),(Cf?b.ctrlKey:b.metaKey)&&"Cmd"!=d&&(a="Cmd-"+a),!c&&b.shiftKey&&"Shift"!=d&&(a="Shift-"+a),a}function Df(a,b){if(ja&&34==a.keyCode&&a["char"])return!1;var c=Da[a.keyCode];return null!=c&&!a.altGraphKey&&Bf(c,a,b)}function Dc(a){return"string"==typeof a?Pb[a]:a}function ob(a,
+b){for(var c=a.doc.sel.ranges,d=[],e=0;e<c.length;e++){for(var f=b(c[e]);d.length&&0>=x(f.from,z(d).to);){var g=d.pop();if(0>x(g.from,f.from)){f.from=g.from;break}}d.push(f)}Y(a,function(){for(var b=d.length-1;0<=b;b--)lb(a.doc,"",d[b].from,d[b].to,"+delete");fb(a)})}function Ef(a,b){var c=w(a.doc,b),d=ma(c);return d!=c&&(b=D(d)),$c(!0,a,d,b,1)}function Ff(a,b){var c=Ef(a,b.line),d=w(a.doc,c.line),e=ya(d,a.doc.direction);return e&&0!=e[0].level?c:(d=Math.max(0,d.text.search(/\S/)),m(c.line,b.line==
+c.line&&b.ch<=d&&b.ch?0:d,c.sticky))}function Ec(a,b,c){if("string"==typeof b&&!(b=Qb[b]))return!1;a.display.input.ensurePolled();var d=a.display.shift,e=!1;try{a.isReadOnly()&&(a.state.suppressEdits=!0),c&&(a.display.shift=!1),e=b(a)!=Fc}finally{a.display.shift=d,a.state.suppressEdits=!1}return e}function Og(a,b,c){for(var d=0;d<a.state.keyMaps.length;d++){var e=nb(b,a.state.keyMaps[d],c,a);if(e)return e}return a.options.extraKeys&&nb(b,a.options.extraKeys,c,a)||nb(b,a.options.keyMap,c,a)}function Rb(a,
+b,c,d){var e=a.state.keySeq;if(e){if(Af(b))return"handled";Pg.set(50,function(){a.state.keySeq==e&&(a.state.keySeq=null,a.display.input.reset())});b=e+" "+b}d=Og(a,b,d);return"multi"==d&&(a.state.keySeq=b),"handled"==d&&P(a,"keyHandled",a,b,c),"handled"!=d&&"multi"!=d||(S(c),rd(a)),e&&!d&&/\'$/.test(b)?(S(c),!0):!!d}function Gf(a,b){var c=Df(b,!0);return!!c&&(b.shiftKey&&!a.state.keySeq?Rb(a,"Shift-"+c,b,function(b){return Ec(a,b,!0)})||Rb(a,c,b,function(b){if("string"==typeof b?/^go[A-Z]/.test(b):
+b.motion)return Ec(a,b)}):Rb(a,c,b,function(b){return Ec(a,b)}))}function Qg(a,b,c){return Rb(a,"'"+c+"'",b,function(b){return Ec(a,b,!0)})}function Hf(a){if(this.curOp.focus=qa(),!K(this,a)){C&&11>B&&27==a.keyCode&&(a.returnValue=!1);var b=a.keyCode;this.display.shift=16==b||a.shiftKey;var c=Gf(this,a);ja&&(Hd=c?b:null,!c&&88==b&&!Rg&&(ha?a.metaKey:a.ctrlKey)&&this.replaceSelection("",null,"cut"));18!=b||/\bCodeMirror-crosshair\b/.test(this.display.lineDiv.className)||Sg(this)}}function Sg(a){function b(a){18!=
+a.keyCode&&a.altKey||(Ra(c,"CodeMirror-crosshair"),aa(document,"keyup",b),aa(document,"mouseover",b))}var c=a.display.lineDiv;Ea(c,"CodeMirror-crosshair");t(document,"keyup",b);t(document,"mouseover",b)}function If(a){16==a.keyCode&&(this.doc.sel.shift=!1);K(this,a)}function Jf(a){if(!(ta(this.display,a)||K(this,a)||a.ctrlKey&&!a.altKey||ha&&a.metaKey)){var b=a.keyCode,c=a.charCode;if(ja&&b==Hd)return Hd=null,void S(a);ja&&(!a.which||10>a.which)&&Gf(this,a)||(b=String.fromCharCode(null==c?b:c),"\b"!=
+b&&(Qg(this,a,b)||this.display.input.onKeyPress(a)))}}function Tg(a,b){var c=+new Date;return Sb&&Sb.compare(c,a,b)?(Tb=Sb=null,"triple"):Tb&&Tb.compare(c,a,b)?(Sb=new Id(c,a,b),Tb=null,"double"):(Tb=new Id(c,a,b),Sb=null,"single")}function Kf(a){var b=this.display;if(!(K(this,a)||b.activeTouch&&b.input.supportsTouch())){if(b.input.ensurePolled(),b.shift=a.shiftKey,ta(b,a))return void(R||(b.scroller.draggable=!1,setTimeout(function(){return b.scroller.draggable=!0},100)));if(!Jd(this,a,"gutterClick",
+!0)){var c=Qa(this,a),d=fe(a),e=c?Tg(c,d):"single";window.focus();1==d&&this.state.selectingText&&this.state.selectingText(a);c&&Ug(this,d,c,e,a)||(1==d?c?Vg(this,c,e,a):(a.target||a.srcElement)==b.scroller&&S(a):2==d?(c&&Ac(this.doc,c),setTimeout(function(){return b.input.focus()},20)):3==d&&(Kd?Lf(this,a):Le(this)))}}}function Ug(a,b,c,d,e){var f="Click";return"double"==d?f="Double"+f:"triple"==d&&(f="Triple"+f),f=(1==b?"Left":2==b?"Middle":"Right")+f,Rb(a,Bf(f,e),e,function(b){if("string"==typeof b&&
+(b=Qb[b]),!b)return!1;var d=!1;try{a.isReadOnly()&&(a.state.suppressEdits=!0),d=b(a,c)!=Fc}finally{a.state.suppressEdits=!1}return d})}function Vg(a,b,c,d){C?setTimeout(Kc(Ke,a),0):a.curOp.focus=qa();var e,f;f=(f=a.getOption("configureMouse"))?f(a,c,d):{};null==f.unit&&(f.unit=(Wg?d.shiftKey&&d.metaKey:d.altKey)?"rectangle":"single"==c?"char":"double"==c?"word":"line");f=((null==f.extend||a.doc.extend)&&(f.extend=a.doc.extend||d.shiftKey),null==f.addNew&&(f.addNew=ha?d.metaKey:d.ctrlKey),null==f.moveOnDrag&&
+(f.moveOnDrag=!(ha?d.altKey:d.ctrlKey)),f);var g=a.doc.sel;a.options.dragDrop&&Xg&&!a.isReadOnly()&&"single"==c&&-1<(e=g.contains(b))&&(0>x((e=g.ranges[e]).from(),b)||0<b.xRel)&&(0<x(e.to(),b)||0>b.xRel)?Yg(a,d,b,f):Zg(a,d,b,f)}function Yg(a,b,c,d){var e=a.display,f=!1,g=L(a,function(b){R&&(e.scroller.draggable=!1);a.state.draggingText=!1;aa(document,"mouseup",g);aa(document,"mousemove",h);aa(e.scroller,"dragstart",k);aa(e.scroller,"drop",g);f||(S(b),d.addNew||Ac(a.doc,c,null,null,d.extend),R||C&&
+9==B?setTimeout(function(){document.body.focus();e.input.focus()},20):e.input.focus())}),h=function(a){f=f||10<=Math.abs(b.clientX-a.clientX)+Math.abs(b.clientY-a.clientY)},k=function(){return f=!0};R&&(e.scroller.draggable=!0);a.state.draggingText=g;g.copy=!d.moveOnDrag;e.scroller.dragDrop&&e.scroller.dragDrop();t(document,"mouseup",g);t(document,"mousemove",h);t(e.scroller,"dragstart",k);t(e.scroller,"drop",g);Le(a);setTimeout(function(){return e.input.focus()},20)}function Mf(a,b,c){if("char"==
+c)return new A(b,b);if("word"==c)return a.findWordAt(b);if("line"==c)return new A(m(b.line,0),v(a.doc,m(b.line+1,0)));a=c(a,b);return new A(a.from,a.to)}function Zg(a,b,c,d){function e(b){if(0!=x(u,b))if(u=b,"rectangle"==d.unit){for(var e=[],f=a.options.tabSize,g=ea(w(k,c.line).text,c.ch,f),h=ea(w(k,b.line).text,b.ch,f),p=Math.min(g,h),g=Math.max(g,h),h=Math.min(c.line,b.line),O=Math.min(a.lastLine(),Math.max(c.line,b.line));h<=O;h++){var r=w(k,h).text,t=Lc(r,p,f);p==g?e.push(new A(m(h,t),m(h,t))):
+r.length>t&&e.push(new A(m(h,t),m(h,Lc(r,g,f))))}e.length||e.push(new A(c,c));Q(k,ka(q.ranges.slice(0,n).concat(e),n),{origin:"*mouse",scroll:!1});a.scrollIntoView(b)}else f=l,p=Mf(a,b,d.unit),b=f.anchor,0<x(p.anchor,b)?(e=p.head,b=ic(f.from(),p.anchor)):(e=p.anchor,b=hc(f.to(),p.head)),f=q.ranges.slice(0),f[n]=new A(v(k,b),e),Q(k,ka(f,n),Ld)}function f(b){var c=++r,g=Qa(a,b,!0,"rectangle"==d.unit);if(g)if(0!=x(g,u)){a.curOp.focus=qa();e(g);var l=td(h,k);(g.line>=l.to||g.line<l.from)&&setTimeout(L(a,
+function(){r==c&&f(b)}),150)}else{var n=b.clientY<O.top?-20:b.clientY>O.bottom?20:0;n&&setTimeout(L(a,function(){r==c&&(h.scroller.scrollTop+=n,f(b))}),50)}}function g(b){a.state.selectingText=!1;r=1/0;S(b);h.input.focus();aa(document,"mousemove",J);aa(document,"mouseup",y);k.history.lastSelOrigin=null}var h=a.display,k=a.doc;S(b);var l,n,q=k.sel,p=q.ranges;(d.addNew&&!d.extend?(n=k.sel.contains(c),l=-1<n?p[n]:new A(c,c)):(l=k.sel.primary(),n=k.sel.primIndex),"rectangle"==d.unit)?(d.addNew||(l=new A(c,
+c)),c=Qa(a,b,!0,!0),n=-1):(b=Mf(a,c,d.unit),l=d.extend?Ed(l,b.anchor,b.head,d.extend):b);d.addNew?-1==n?(n=p.length,Q(k,ka(p.concat([l]),n),{scroll:!1,origin:"*mouse"})):1<p.length&&p[n].empty()&&"char"==d.unit&&!d.extend?(Q(k,ka(p.slice(0,n).concat(p.slice(n+1)),0),{scroll:!1,origin:"*mouse"}),q=k.sel):Fd(k,n,l,Ld):(n=0,Q(k,new ca([l],0),Ld),q=k.sel);var u=c,O=h.wrapper.getBoundingClientRect(),r=0,J=L(a,function(a){fe(a)?f(a):g(a)}),y=L(a,g);a.state.selectingText=y;t(document,"mousemove",J);t(document,
+"mouseup",y)}function Jd(a,b,c,d){var e,f;try{e=b.clientX,f=b.clientY}catch(g){return!1}if(e>=Math.floor(a.display.gutters.getBoundingClientRect().right))return!1;d&&S(b);d=a.display;var h=d.lineDiv.getBoundingClientRect();if(f>h.bottom||!fa(a,c))return ad(b);f-=h.top-d.viewOffset;for(h=0;h<a.options.gutters.length;++h){var k=d.gutters.childNodes[h];if(k&&k.getBoundingClientRect().right>=e)return F(a,c,a,Ha(a.doc,f),a.options.gutters[h],b),ad(b)}}function Lf(a,b){var c;(c=ta(a.display,b))||(c=!!fa(a,
+"gutterContextMenu")&&Jd(a,b,"gutterContextMenu",!1));c||K(a,b,"contextmenu")||a.display.input.onContextMenu(b)}function Nf(a){a.display.wrapper.className=a.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+a.options.theme.replace(/(^|\s)\s*/g," cm-s-");Bb(a)}function Ub(a){We(a);V(a);Ne(a)}function $g(a,b,c){!b!=!(c&&c!=pb)&&(c=a.display.dragFunctions,b=b?t:aa,b(a.display.scroller,"dragstart",c.start),b(a.display.scroller,"dragenter",c.enter),b(a.display.scroller,"dragover",c.over),b(a.display.scroller,
+"dragleave",c.leave),b(a.display.scroller,"drop",c.drop))}function ah(a){a.options.lineWrapping?(Ea(a.display.wrapper,"CodeMirror-wrap"),a.display.sizer.style.minWidth="",a.display.sizerWidth=null):(Ra(a.display.wrapper,"CodeMirror-wrap"),Wc(a));qd(a);V(a);Bb(a);setTimeout(function(){return gb(a)},100)}function E(a,b){var c=this;if(!(this instanceof E))return new E(a,b);this.options=b=b?Fa(b):{};Fa(Of,b,!1);zd(b);var d=b.value;"string"==typeof d&&(d=new W(d,b.mode,null,b.lineSeparator,b.direction));
+this.doc=d;var e=new E.inputStyles[b.inputStyle](this),e=this.display=new eg(a,d,e);e.wrapper.CodeMirror=this;We(this);Nf(this);b.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap");Se(this);this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,selectingText:!1,draggingText:!1,highlight:new Wa,keySeq:null,specialChars:null};b.autofocus&&!rb&&e.input.focus();C&&11>B&&setTimeout(function(){return c.display.input.reset(!0)},
+20);bh(this);Pf||(Kg(),Pf=!0);Ta(this);this.curOp.forceUpdate=!0;bf(this,d);b.autofocus&&!rb||this.hasFocus()?setTimeout(Kc(sd,this),20):Db(this);for(var f in Gc)Gc.hasOwnProperty(f)&&Gc[f](c,b[f],pb);Oe(this);b.finishInit&&b.finishInit(this);for(d=0;d<Md.length;++d)Md[d](c);Ua(this);R&&b.lineWrapping&&"optimizelegibility"==getComputedStyle(e.lineDiv).textRendering&&(e.lineDiv.style.textRendering="auto")}function bh(a){function b(){d.activeTouch&&(e=setTimeout(function(){return d.activeTouch=null},
+1E3),f=d.activeTouch,f.end=+new Date)}function c(a,b){if(null==b.left)return!0;var c=b.left-a.left,d=b.top-a.top;return 400<c*c+d*d}var d=a.display;t(d.scroller,"mousedown",L(a,Kf));C&&11>B?t(d.scroller,"dblclick",L(a,function(b){if(!K(a,b)){var c=Qa(a,b);!c||Jd(a,b,"gutterClick",!0)||ta(a.display,b)||(S(b),b=a.findWordAt(c),Ac(a.doc,b.anchor,b.head))}})):t(d.scroller,"dblclick",function(b){return K(a,b)||S(b)});Kd||t(d.scroller,"contextmenu",function(b){return Lf(a,b)});var e,f={end:0};t(d.scroller,
+"touchstart",function(b){var c;if(c=!K(a,b))1!=b.touches.length?c=!1:(c=b.touches[0],c=1>=c.radiusX&&1>=c.radiusY),c=!c;c&&(d.input.ensurePolled(),clearTimeout(e),c=+new Date,d.activeTouch={start:c,moved:!1,prev:300>=c-f.end?f:null},1==b.touches.length&&(d.activeTouch.left=b.touches[0].pageX,d.activeTouch.top=b.touches[0].pageY))});t(d.scroller,"touchmove",function(){d.activeTouch&&(d.activeTouch.moved=!0)});t(d.scroller,"touchend",function(e){var f=d.activeTouch;if(f&&!ta(d,e)&&null!=f.left&&!f.moved&&
+300>new Date-f.start){var g=a.coordsChar(d.activeTouch,"page"),f=!f.prev||c(f,f.prev)?new A(g,g):!f.prev.prev||c(f,f.prev.prev)?a.findWordAt(g):new A(m(g.line,0),v(a.doc,m(g.line+1,0)));a.setSelection(f.anchor,f.head);a.focus();S(e)}b()});t(d.scroller,"touchcancel",b);t(d.scroller,"scroll",function(){d.scroller.clientHeight&&(Fb(a,d.scroller.scrollTop),Sa(a,d.scroller.scrollLeft,!0),F(a,"scroll",a))});t(d.scroller,"mousewheel",function(b){return Ye(a,b)});t(d.scroller,"DOMMouseScroll",function(b){return Ye(a,
+b)});t(d.wrapper,"scroll",function(){return d.wrapper.scrollTop=d.wrapper.scrollLeft=0});d.dragFunctions={enter:function(b){K(a,b)||vb(b)},over:function(b){if(!K(a,b)){var c=Qa(a,b);if(c){var d=document.createDocumentFragment();Je(a,c,d);a.display.dragCursor||(a.display.dragCursor=r("div",null,"CodeMirror-cursors CodeMirror-dragcursors"),a.display.lineSpace.insertBefore(a.display.dragCursor,a.display.cursorDiv));Z(a.display.dragCursor,d)}vb(b)}},start:function(b){if(C&&(!a.state.draggingText||100>
++new Date-yf))b=void vb(b);else{if(!K(a,b)&&!ta(a.display,b)&&(b.dataTransfer.setData("Text",a.getSelection()),b.dataTransfer.effectAllowed="copyMove",b.dataTransfer.setDragImage&&!Qf)){var c=r("img",null,null,"position: fixed; left: 0; top: 0;");c.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw\x3d\x3d";ja&&(c.width=c.height=1,a.display.wrapper.appendChild(c),c._top=c.offsetTop);b.dataTransfer.setDragImage(c,0,0);ja&&c.parentNode.removeChild(c)}b=void 0}return b},drop:L(a,
+Jg),leave:function(b){K(a,b)||xf(a)}};var g=d.input.getField();t(g,"keyup",function(b){return If.call(a,b)});t(g,"keydown",L(a,Hf));t(g,"keypress",L(a,Jf));t(g,"focus",function(b){return sd(a,b)});t(g,"blur",function(b){return Db(a,b)})}function Vb(a,b,c,d){var e,f=a.doc;null==c&&(c="add");"smart"==c&&(f.mode.indent?e=wb(a,b).state:c="prev");var g=a.options.tabSize,h=w(f,b),k=ea(h.text,null,g);h.stateAfter&&(h.stateAfter=null);var l,n=h.text.match(/^\s*/)[0];if(d||/\S/.test(h.text)){if("smart"==c&&
+((l=f.mode.indent(e,h.text.slice(n.length),h.text))==Fc||150<l)){if(!d)return;c="prev"}}else l=0,c="not";"prev"==c?l=b>f.first?ea(w(f,b-1).text,null,g):0:"add"==c?l=k+a.options.indentUnit:"subtract"==c?l=k-a.options.indentUnit:"number"==typeof c&&(l=k+c);l=Math.max(0,l);c="";d=0;if(a.options.indentWithTabs)for(a=Math.floor(l/g);a;--a)d+=g,c+="\t";if(d<l&&(c+=Mc(l-d)),c!=n)return lb(f,c,m(b,0),m(b,n.length),"+input"),h.stateAfter=null,!0;for(g=0;g<f.sel.ranges.length;g++)if(h=f.sel.ranges[g],h.head.line==
+b&&h.head.ch<n.length){b=m(b,n.length);Fd(f,g,new A(b,b));break}}function Rf(a){da=a}function Nd(a,b,c,d,e){var f=a.doc;a.display.shift=!1;d||(d=f.sel);var g=a.state.pasteIncoming||"paste"==e,h=Od(b),k=null;if(g&&1<d.ranges.length)if(da&&da.text.join("\n")==b){if(0==d.ranges.length%da.text.length)for(var k=[],l=0;l<da.text.length;l++)k.push(f.splitLines(da.text[l]))}else h.length==d.ranges.length&&a.options.pasteLinesPerSelection&&(k=ec(h,function(a){return[a]}));for(var n,l=d.ranges.length-1;0<=
+l;l--){n=d.ranges[l];var q=n.from(),p=n.to();n.empty()&&(c&&0<c?q=m(q.line,q.ch-c):a.state.overwrite&&!g?p=m(p.line,Math.min(w(f,p.line).text.length,p.ch+z(h).length)):da&&da.lineWise&&da.text.join("\n")==b&&(q=p=m(q.line,0)));n=a.curOp.updateInput;q={from:q,to:p,text:k?k[l%k.length]:h,origin:e||(g?"paste":a.state.cutIncoming?"cut":"+input")};kb(a.doc,q);P(a,"inputRead",a,q)}b&&!g&&Sf(a,b);fb(a);a.curOp.updateInput=n;a.curOp.typing=!0;a.state.pasteIncoming=a.state.cutIncoming=!1}function Tf(a,b){var c=
+a.clipboardData&&a.clipboardData.getData("Text");if(c)return a.preventDefault(),b.isReadOnly()||b.options.disableInput||Y(b,function(){return Nd(b,c,0,null,"paste")}),!0}function Sf(a,b){if(a.options.electricChars&&a.options.smartIndent)for(var c=a.doc.sel,d=c.ranges.length-1;0<=d;d--){var e=c.ranges[d];if(!(100<e.head.ch||d&&c.ranges[d-1].head.line==e.head.line)){var f=a.getModeAt(e.head),g=!1;if(f.electricChars)for(var h=0;h<f.electricChars.length;h++){if(-1<b.indexOf(f.electricChars.charAt(h))){g=
+Vb(a,e.head.line,"smart");break}}else f.electricInput&&f.electricInput.test(w(a.doc,e.head.line).text.slice(0,e.head.ch))&&(g=Vb(a,e.head.line,"smart"));g&&P(a,"electricInput",a,e.head.line)}}}function Uf(a){for(var b=[],c=[],d=0;d<a.doc.sel.ranges.length;d++){var e=a.doc.sel.ranges[d].head.line,e={anchor:m(e,0),head:m(e+1,0)};c.push(e);b.push(a.getRange(e.anchor,e.head))}return{text:b,ranges:c}}function Vf(a,b){a.setAttribute("autocorrect","off");a.setAttribute("autocapitalize","off");a.setAttribute("spellcheck",
+!!b)}function Wf(){var a=r("textarea",null,null,"position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none"),b=r("div",[a],null,"overflow: hidden; position: relative; width: 3px; height: 0px;");return R?a.style.width="1000px":a.setAttribute("wrap","off"),Wb&&(a.style.border="1px solid black"),Vf(a),b}function Pd(a,b,c,d,e){function f(d){var f;if(null==(f=e?be(a.cm,k,b,c):Zc(k,b,c))){d||(d=b.line+c,d=!(!(d<a.first||d>=a.first+a.size)&&(b=new m(d,b.ch,b.sticky),k=w(a,d))));
+if(d)return!1;b=$c(e,a.cm,k,b.line,c)}else b=f;return!0}var g=b,h=c,k=w(a,b.line);if("char"==d)f();else if("column"==d)f(!0);else if("word"==d||"group"==d){var l=null;d="group"==d;for(var n=a.cm&&a.cm.getHelper(b,"wordChars"),q=!0;!(0>c)||f(!q);q=!1){var p=k.text.charAt(b.ch)||"\n",p=fc(p,n)?"w":d&&"\n"==p?"n":!d||/\s/.test(p)?null:"p";if(!d||q||p||(p="s"),l&&l!=p){0>c&&(c=1,f(),b.sticky="after");break}if(p&&(l=p),0<c&&!f(!q))break}}h=Gd(a,b,g,h,!0);return Rc(g,h)&&(h.hitSide=!0),h}function Xf(a,
+b,c,d){var e,f=a.doc,g=b.left;"page"==d?(d=Math.min(a.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),d=Math.max(d-.5*Oa(a.display),3),e=(0<c?b.bottom:b.top)+c*d):"line"==d&&(e=0<c?b.bottom+3:b.top-3);for(var h;h=od(a,g,e),h.outside;){if(0>c?0>=e:e>=f.height){h.hitSide=!0;break}e+=5*c}return h}function Yf(a,b){var c=ld(a,b.line);if(!c||c.hidden)return null;var d=w(a.doc,b.line),c=ye(c,d,b.line),d=ya(d,a.doc.direction),e="left";d&&(e=Xc(d,b.ch)%2?"right":"left");
+c=ze(c.map,b.ch,e);return c.offset="right"==c.collapse?c.end:c.start,c}function ch(a){for(;a;a=a.parentNode)if(/CodeMirror-gutter-wrapper/.test(a.className))return!0;return!1}function qb(a,b){return b&&(a.bad=!0),a}function dh(a,b,c,d,e){function f(a){return function(b){return b.id==a}}function g(){l&&(k+=n,l=!1)}function h(b){if(1==b.nodeType){var c=b.getAttribute("cm-text");if(null!=c)(b=c||b.textContent.replace(/\u200b/g,""))&&(g(),k+=b);else{var u;if(c=b.getAttribute("cm-marker"))b=a.findMarks(m(d,
+0),m(e+1,0),f(+c)),b.length&&(u=b[0].find())&&(b=Ga(a.doc,u.from,u.to).join(n))&&(g(),k+=b);else if("false"!=b.getAttribute("contenteditable")){(u=/^(pre|div|p)$/i.test(b.nodeName))&&g();for(c=0;c<b.childNodes.length;c++)h(b.childNodes[c]);u&&(l=!0)}}}else 3==b.nodeType&&(b=b.nodeValue)&&(g(),k+=b)}for(var k="",l=!1,n=a.doc.lineSeparator();h(b),b!=c;)b=b.nextSibling;return k}function Hc(a,b,c){var d;if(b==a.display.lineDiv){if(!(d=a.display.lineDiv.childNodes[c]))return qb(a.clipPos(m(a.display.viewTo-
+1)),!0);b=null;c=0}else for(d=b;;d=d.parentNode){if(!d||d==a.display.lineDiv)return null;if(d.parentNode&&d.parentNode==a.display.lineDiv)break}for(var e=0;e<a.display.view.length;e++){var f=a.display.view[e];if(f.node==d)return eh(f,b,c)}}function eh(a,b,c){function d(b,c,d){for(var e=-1;e<(l?l.length:0);e++)for(var f=0>e?k.map:l[e],g=0;g<f.length;g+=3){var h=f[g+2];if(h==b||h==c)return c=D(0>e?a.line:a.rest[e]),e=f[g]+d,(0>d||h!=b)&&(e=f[g+(d?1:0)]),m(c,e)}}var e=a.text.firstChild,f=!1;if(!b||!va(e,
+b))return qb(m(D(a.line),0),!0);if(b==e&&(f=!0,b=e.childNodes[c],c=0,!b))return c=a.rest?z(a.rest):a.line,qb(m(D(c),c.text.length),f);var g=3==b.nodeType?b:null,h=b;for(g||1!=b.childNodes.length||3!=b.firstChild.nodeType||(g=b.firstChild,c&&(c=g.nodeValue.length));h.parentNode!=e;)h=h.parentNode;var k=a.measure,l=k.maps;if(b=d(g,h,c))return qb(b,f);e=h.nextSibling;for(g=g?g.nodeValue.length-c:0;e;e=e.nextSibling){if(b=d(e,e.firstChild,0))return qb(m(b.line,b.ch-g),f);g+=e.textContent.length}for(h=
+h.previousSibling;h;h=h.previousSibling){if(b=d(h,h.firstChild,-1))return qb(m(b.line,b.ch+c),f);c+=h.textContent.length}}var U=navigator.userAgent,Zf=navigator.platform,wa=/gecko\/\d/i.test(U),$f=/MSIE \d/.test(U),ag=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(U),Xb=/Edge\/(\d+)/.exec(U),C=$f||ag||Xb,B=C&&($f?document.documentMode||6:+(Xb||ag)[1]),R=!Xb&&/WebKit\//.test(U),fh=R&&/Qt\/\d+\.\d+/.test(U),pc=!Xb&&/Chrome\//.test(U),ja=/Opera\//.test(U),Qf=/Apple Computer/.test(navigator.vendor),gh=
+/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(U),yg=/PhantomJS/.test(U),Wb=!Xb&&/AppleWebKit/.test(U)&&/Mobile\/\w+/.test(U),qc=/Android/.test(U),rb=Wb||qc||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(U),ha=Wb||/Mac/.test(Zf),Wg=/\bCrOS\b/.test(U),hh=/win/i.test(Zf),Xa=ja&&U.match(/Version\/(\d*\.\d*)/);Xa&&(Xa=Number(Xa[1]));Xa&&15<=Xa&&(ja=!1,R=!0);var db,Cf=ha&&(fh||ja&&(null==Xa||12.11>Xa)),Kd=wa||C&&9<=B,Ra=function(a,b){var c=a.className,d=ga(b).exec(c);if(d){var e=c.slice(d.index+d[0].length);
+a.className=c.slice(0,d.index)+(e?d[1]+e:"")}};db=document.createRange?function(a,b,c,d){var e=document.createRange();return e.setEnd(d||a,c),e.setStart(a,b),e}:function(a,b,c){var d=document.body.createTextRange();try{d.moveToElementText(a.parentNode)}catch(e){return d}return d.collapse(!0),d.moveEnd("character",c),d.moveStart("character",b),d};var Yb=function(a){a.select()};Wb?Yb=function(a){a.selectionStart=0;a.selectionEnd=a.value.length}:C&&(Yb=function(a){try{a.select()}catch(b){}});var Wa=
+function(){this.id=null};Wa.prototype.set=function(a,b){clearTimeout(this.id);this.id=setTimeout(b,a)};var bd,hd,Ud=30,Fc={toString:function(){return"CodeMirror.Pass"}},pa={scroll:!1},Ld={origin:"*mouse"},Zb={origin:"+move"},dc=[""],cg=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/,dg=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/,
+qf=!1,xa=!1,ub=null,hg=function(){function a(a){return 247>=a?c.charAt(a):1424<=a&&1524>=a?"R":1536<=a&&1785>=a?d.charAt(a-1536):1774<=a&&2220>=a?"r":8192<=a&&8203>=a?"w":8204==a?"b":"L"}function b(a,b,c){this.level=a;this.from=b;this.to=c}var c="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",d="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111",
+e=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,f=/[stwN]/,g=/[LRr]/,h=/[Lb1n]/,k=/[1n]/;return function(c,d){var q="ltr"==d?"L":"R";if(0==c.length||"ltr"==d&&!e.test(c))return!1;for(var p=c.length,u=[],m=0;m<p;++m)u.push(a(c.charCodeAt(m)));for(var m=0,r=q;m<p;++m){var t=u[m];"m"==t?u[m]=r:r=t}m=0;for(r=q;m<p;++m)t=u[m],"1"==t&&"r"==r?u[m]="n":g.test(t)&&(r=t,"r"==t&&(u[m]="R"));m=1;for(r=u[0];m<p-1;++m)t=u[m],"+"==t&&"1"==r&&"1"==u[m+1]?u[m]="1":","!=t||r!=u[m+1]||"1"!=r&&"n"!=r||(u[m]=r),r=t;for(m=
+0;m<p;++m)if(r=u[m],","==r)u[m]="N";else if("%"==r){r=void 0;for(r=m+1;r<p&&"%"==u[r];++r);for(t=m&&"!"==u[m-1]||r<p&&"1"==u[r]?"1":"N";m<r;++m)u[m]=t;m=r-1}m=0;for(r=q;m<p;++m)t=u[m],"L"==r&&"1"==t?u[m]="L":g.test(t)&&(r=t);for(r=0;r<p;++r)if(f.test(u[r])){m=void 0;for(m=r+1;m<p&&f.test(u[m]);++m);t="L"==(r?u[r-1]:q);for(t=t==("L"==(m<p?u[m]:q))?t?"L":"R":q;r<m;++r)u[r]=t;r=m-1}for(var v,q=[],m=0;m<p;)if(h.test(u[m])){r=m;for(++m;m<p&&h.test(u[m]);++m);q.push(new b(0,r,m))}else{var w=m,r=q.length;
+for(++m;m<p&&"L"!=u[m];++m);for(t=w;t<m;)if(k.test(u[t])){w<t&&q.splice(r,0,new b(1,w,t));w=t;for(++t;t<m&&k.test(u[t]);++t);q.splice(r,0,new b(2,w,t));w=t}else++t;w<m&&q.splice(r,0,new b(1,w,m))}return 1==q[0].level&&(v=c.match(/^\s+/))&&(q[0].from=v[0].length,q.unshift(new b(0,0,v[0].length))),1==z(q).level&&(v=c.match(/\s+$/))&&(z(q).to-=v[0].length,q.push(new b(0,p-v[0].length,p))),"rtl"==d?q.reverse():q}}(),lc=[],t=function(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent?a.attachEvent("on"+
+b,c):(a=a._handlers||(a._handlers={}),a[b]=(a[b]||lc).concat(c))},Xg=function(){if(C&&9>B)return!1;var a=r("div");return"draggable"in a||"dragDrop"in a}(),Od=3!="\n\nb".split(/\n/).length?function(a){for(var b=0,c=[],d=a.length;b<=d;){var e=a.indexOf("\n",b);-1==e&&(e=a.length);var f=a.slice(b,"\r"==a.charAt(e-1)?e-1:e),g=f.indexOf("\r");-1!=g?(c.push(f.slice(0,g)),b+=g+1):(c.push(f),b=e+1)}return c}:function(a){return a.split(/\r\n?|\n/)},ih=window.getSelection?function(a){try{return a.selectionStart!=
+a.selectionEnd}catch(b){return!1}}:function(a){var b;try{b=a.ownerDocument.selection.createRange()}catch(c){}return!(!b||b.parentElement()!=a)&&0!=b.compareEndPoints("StartToEnd",b)},Rg=function(){var a=r("div");return"oncopy"in a||(a.setAttribute("oncopy","return;"),"function"==typeof a.oncopy)}(),nd=null,cd={},bb={},cb={},H=function(a,b,c){this.pos=this.start=0;this.string=a;this.tabSize=b||8;this.lineStart=this.lastColumnPos=this.lastColumnValue=0;this.lineOracle=c};H.prototype.eol=function(){return this.pos>=
+this.string.length};H.prototype.sol=function(){return this.pos==this.lineStart};H.prototype.peek=function(){return this.string.charAt(this.pos)||void 0};H.prototype.next=function(){if(this.pos<this.string.length)return this.string.charAt(this.pos++)};H.prototype.eat=function(a){var b=this.string.charAt(this.pos);if("string"==typeof a?b==a:b&&(a.test?a.test(b):a(b)))return++this.pos,b};H.prototype.eatWhile=function(a){for(var b=this.pos;this.eat(a););return this.pos>b};H.prototype.eatSpace=function(){for(var a=
+this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>a};H.prototype.skipToEnd=function(){this.pos=this.string.length};H.prototype.skipTo=function(a){a=this.string.indexOf(a,this.pos);if(-1<a)return this.pos=a,!0};H.prototype.backUp=function(a){this.pos-=a};H.prototype.column=function(){return this.lastColumnPos<this.start&&(this.lastColumnValue=ea(this.string,this.start,this.tabSize,this.lastColumnPos,this.lastColumnValue),this.lastColumnPos=this.start),this.lastColumnValue-
+(this.lineStart?ea(this.string,this.lineStart,this.tabSize):0)};H.prototype.indentation=function(){return ea(this.string,null,this.tabSize)-(this.lineStart?ea(this.string,this.lineStart,this.tabSize):0)};H.prototype.match=function(a,b,c){if("string"!=typeof a)return(a=this.string.slice(this.pos).match(a))&&0<a.index?null:(a&&!1!==b&&(this.pos+=a[0].length),a);var d=function(a){return c?a.toLowerCase():a};if(d(this.string.substr(this.pos,a.length))==d(a))return!1!==b&&(this.pos+=a.length),!0};H.prototype.current=
+function(){return this.string.slice(this.start,this.pos)};H.prototype.hideFirstChars=function(a,b){this.lineStart+=a;try{return b()}finally{this.lineStart-=a}};H.prototype.lookAhead=function(a){var b=this.lineOracle;return b&&b.lookAhead(a)};var nc=function(a,b){this.state=a;this.lookAhead=b},sa=function(a,b,c,d){this.state=b;this.doc=a;this.line=c;this.maxLookAhead=d||0};sa.prototype.lookAhead=function(a){var b=this.doc.getLine(this.line+a);return null!=b&&a>this.maxLookAhead&&(this.maxLookAhead=
+a),b};sa.prototype.nextLine=function(){this.line++;0<this.maxLookAhead&&this.maxLookAhead--};sa.fromSaved=function(a,b,c){return b instanceof nc?new sa(a,La(a.mode,b.state),c,b.lookAhead):new sa(a,La(a.mode,b),c)};sa.prototype.save=function(a){a=!1!==a?La(this.doc.mode,this.state):this.state;return 0<this.maxLookAhead?new nc(a,this.maxLookAhead):a};var me=function(a,b,c){this.start=a.start;this.end=a.pos;this.string=a.current();this.type=b||null;this.state=c},hb=function(a,b,c){this.text=a;Yd(this,
+b);this.height=c?c(this):1};hb.prototype.lineNo=function(){return D(this)};ab(hb);var Pa,og={},ng={},eb=null,xb=null,Ae={left:0,right:0,top:0,bottom:0},Ya=function(a,b,c){this.cm=c;var d=this.vert=r("div",[r("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),e=this.horiz=r("div",[r("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");a(d);a(e);t(d,"scroll",function(){d.clientHeight&&b(d.scrollTop,"vertical")});t(e,"scroll",function(){e.clientWidth&&b(e.scrollLeft,"horizontal")});
+this.checkedZeroWidth=!1;C&&8>B&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};Ya.prototype.update=function(a){var b=a.scrollWidth>a.clientWidth+1,c=a.scrollHeight>a.clientHeight+1,d=a.nativeBarWidth;c?(this.vert.style.display="block",this.vert.style.bottom=b?d+"px":"0",this.vert.firstChild.style.height=Math.max(0,a.scrollHeight-a.clientHeight+(a.viewHeight-(b?d:0)))+"px"):(this.vert.style.display="",this.vert.firstChild.style.height="0");b?(this.horiz.style.display="block",this.horiz.style.right=
+c?d+"px":"0",this.horiz.style.left=a.barLeft+"px",this.horiz.firstChild.style.width=Math.max(0,a.scrollWidth-a.clientWidth+(a.viewWidth-a.barLeft-(c?d:0)))+"px"):(this.horiz.style.display="",this.horiz.firstChild.style.width="0");return!this.checkedZeroWidth&&0<a.clientHeight&&(0==d&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:c?d:0,bottom:b?d:0}};Ya.prototype.setScrollLeft=function(a){this.horiz.scrollLeft!=a&&(this.horiz.scrollLeft=a);this.disableHoriz&&this.enableZeroWidthBar(this.horiz,
+this.disableHoriz,"horiz")};Ya.prototype.setScrollTop=function(a){this.vert.scrollTop!=a&&(this.vert.scrollTop=a);this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")};Ya.prototype.zeroWidthHack=function(){this.horiz.style.height=this.vert.style.width=ha&&!gh?"12px":"18px";this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none";this.disableHoriz=new Wa;this.disableVert=new Wa};Ya.prototype.enableZeroWidthBar=function(a,b,c){function d(){var e=a.getBoundingClientRect();
+("vert"==c?document.elementFromPoint(e.right-1,(e.top+e.bottom)/2):document.elementFromPoint((e.right+e.left)/2,e.bottom-1))!=a?a.style.pointerEvents="none":b.set(1E3,d)}a.style.pointerEvents="auto";b.set(1E3,d)};Ya.prototype.clear=function(){var a=this.horiz.parentNode;a.removeChild(this.horiz);a.removeChild(this.vert)};var $b=function(){};$b.prototype.update=function(){return{bottom:0,right:0}};$b.prototype.setScrollLeft=function(){};$b.prototype.setScrollTop=function(){};$b.prototype.clear=function(){};
+var Te={"native":Ya,"null":$b},xg=0,vc=function(a,b,c){var d=a.display;this.viewport=b;this.visible=td(d,a.doc,b);this.editorIsHidden=!d.wrapper.offsetWidth;this.wrapperHeight=d.wrapper.clientHeight;this.wrapperWidth=d.wrapper.clientWidth;this.oldDisplayWidth=Ma(a);this.force=c;this.dims=md(a);this.events=[]};vc.prototype.signal=function(a,b){fa(a,b)&&this.events.push(arguments)};vc.prototype.finish=function(){for(var a=0;a<this.events.length;a++)F.apply(null,this.events[a])};var xc=0,ba=null;C?ba=
+-.53:wa?ba=15:pc?ba=-.7:Qf&&(ba=-1/3);var ca=function(a,b){this.ranges=a;this.primIndex=b};ca.prototype.primary=function(){return this.ranges[this.primIndex]};ca.prototype.equals=function(a){if(a==this)return!0;if(a.primIndex!=this.primIndex||a.ranges.length!=this.ranges.length)return!1;for(var b=0;b<this.ranges.length;b++){var c=this.ranges[b],d=a.ranges[b];if(!Rc(c.anchor,d.anchor)||!Rc(c.head,d.head))return!1}return!0};ca.prototype.deepCopy=function(){for(var a=[],b=0;b<this.ranges.length;b++)a[b]=
+new A(Sc(this.ranges[b].anchor),Sc(this.ranges[b].head));return new ca(a,this.primIndex)};ca.prototype.somethingSelected=function(){for(var a=0;a<this.ranges.length;a++)if(!this.ranges[a].empty())return!0;return!1};ca.prototype.contains=function(a,b){b||(b=a);for(var c=0;c<this.ranges.length;c++){var d=this.ranges[c];if(0<=x(b,d.from())&&0>=x(a,d.to()))return c}return-1};var A=function(a,b){this.anchor=a;this.head=b};A.prototype.from=function(){return ic(this.anchor,this.head)};A.prototype.to=function(){return hc(this.anchor,
+this.head)};A.prototype.empty=function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch};Lb.prototype={chunkSize:function(){return this.lines.length},removeInner:function(a,b){for(var c=a,d=a+b;c<d;++c){var e=this.lines[c];this.height-=e.height;var f=e;f.parent=null;Xd(f);P(e,"delete")}this.lines.splice(a,b)},collapse:function(a){a.push.apply(a,this.lines)},insertInner:function(a,b,c){this.height+=c;this.lines=this.lines.slice(0,a).concat(b).concat(this.lines.slice(a));for(a=
+0;a<b.length;++a)b[a].parent=this},iterN:function(a,b,c){for(b=a+b;a<b;++a)if(c(this.lines[a]))return!0}};Mb.prototype={chunkSize:function(){return this.size},removeInner:function(a,b){this.size-=b;for(var c=0;c<this.children.length;++c){var d=this.children[c],e=d.chunkSize();if(a<e){var f=Math.min(b,e-a),g=d.height;if(d.removeInner(a,f),this.height-=g-d.height,e==f&&(this.children.splice(c--,1),d.parent=null),0==(b-=f))break;a=0}else a-=e}25>this.size-b&&(1<this.children.length||!(this.children[0]instanceof
+Lb))&&(c=[],this.collapse(c),this.children=[new Lb(c)],this.children[0].parent=this)},collapse:function(a){for(var b=0;b<this.children.length;++b)this.children[b].collapse(a)},insertInner:function(a,b,c){this.size+=b.length;this.height+=c;for(var d=0;d<this.children.length;++d){var e=this.children[d],f=e.chunkSize();if(a<=f){if(e.insertInner(a,b,c),e.lines&&50<e.lines.length){for(b=a=e.lines.length%25+25;b<e.lines.length;)c=new Lb(e.lines.slice(b,b+=25)),e.height-=c.height,this.children.splice(++d,
+0,c),c.parent=this;e.lines=e.lines.slice(0,a);this.maybeSpill()}break}a-=f}},maybeSpill:function(){if(!(10>=this.children.length)){var a=this;do{var b=a.children.splice(a.children.length-5,5),b=new Mb(b);if(a.parent){a.size-=b.size;a.height-=b.height;var c=N(a.parent.children,a);a.parent.children.splice(c+1,0,b)}else c=new Mb(a.children),c.parent=a,a.children=[c,b],a=c;b.parent=a.parent}while(10<a.children.length);a.parent.maybeSpill()}},iterN:function(a,b,c){for(var d=0;d<this.children.length;++d){var e=
+this.children[d],f=e.chunkSize();if(a<f){f=Math.min(b,f-a);if(e.iterN(a,f,c))return!0;if(0==(b-=f))break;a=0}else a-=f}}};var Nb=function(a,b,c){if(c)for(var d in c)c.hasOwnProperty(d)&&(this[d]=c[d]);this.doc=a;this.node=b};Nb.prototype.clear=function(){var a=this.doc.cm,b=this.line.widgets,c=this.line,d=D(c);if(null!=d&&b){for(var e=0;e<b.length;++e)b[e]==this&&b.splice(e--,1);b.length||(c.widgets=null);var f=zb(this);la(c,Math.max(0,c.height-f));a&&(Y(a,function(){var b=-f;na(c)<(a.curOp&&a.curOp.scrollTop||
+a.doc.scrollTop)&&tc(a,b);Aa(a,d,"widget")}),P(a,"lineWidgetCleared",a,this,d))}};Nb.prototype.changed=function(){var a=this,b=this.height,c=this.doc.cm,d=this.line;this.height=null;var e=zb(this)-b;e&&(la(d,d.height+e),c&&Y(c,function(){c.curOp.forceUpdate=!0;na(d)<(c.curOp&&c.curOp.scrollTop||c.doc.scrollTop)&&tc(c,e);P(c,"lineWidgetChanged",c,a,D(d))}))};ab(Nb);var vf=0,Ca=function(a,b){this.lines=[];this.type=b;this.doc=a;this.id=++vf};Ca.prototype.clear=function(){if(!this.explicitlyCleared){var a=
+this.doc.cm,b=a&&!a.curOp;if(b&&Ta(a),fa(this,"clear")){var c=this.find();c&&P(this,"clear",c.from,c.to)}for(var d=c=null,e=0;e<this.lines.length;++e){var f=this.lines[e],g=tb(f.markedSpans,this);a&&!this.collapsed?Aa(a,D(f),"text"):a&&(null!=g.to&&(d=D(f)),null!=g.from&&(c=D(f)));for(var h=f,k=f.markedSpans,l=g,n=void 0,m=0;m<k.length;++m)k[m]!=l&&(n||(n=[])).push(k[m]);h.markedSpans=n;null==g.from&&this.collapsed&&!Ja(this.doc,f)&&a&&la(f,Oa(a.display))}if(a&&this.collapsed&&!a.options.lineWrapping)for(e=
+0;e<this.lines.length;++e)f=ma(this.lines[e]),g=kc(f),g>a.display.maxLineLength&&(a.display.maxLine=f,a.display.maxLineLength=g,a.display.maxLineChanged=!0);null!=c&&a&&this.collapsed&&V(a,c,d+1);this.lines.length=0;this.explicitlyCleared=!0;this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,a&&mf(a.doc));a&&P(a,"markerCleared",a,this,c,d);b&&Ua(a);this.parent&&this.parent.clear()}};Ca.prototype.find=function(a,b){null==a&&"bookmark"==this.type&&(a=1);for(var c,d,e=0;e<this.lines.length;++e){var f=
+this.lines[e],g=tb(f.markedSpans,this);if(null!=g.from&&(c=m(b?f:D(f),g.from),-1==a))return c;if(null!=g.to&&(d=m(b?f:D(f),g.to),1==a))return d}return c&&{from:c,to:d}};Ca.prototype.changed=function(){var a=this,b=this.find(-1,!0),c=this,d=this.doc.cm;b&&d&&Y(d,function(){var e=b.line,f=D(b.line),f=ld(d,f);(f&&(Be(f),d.curOp.selectionChanged=d.curOp.forceUpdate=!0),d.curOp.updateMaxLine=!0,Ja(c.doc,e)||null==c.height)||(f=c.height,c.height=null,(f=zb(c)-f)&&la(e,e.height+f));P(d,"markerChanged",d,
+a)})};Ca.prototype.attachLine=function(a){if(!this.lines.length&&this.doc.cm){var b=this.doc.cm.curOp;b.maybeHiddenMarkers&&-1!=N(b.maybeHiddenMarkers,this)||(b.maybeUnhiddenMarkers||(b.maybeUnhiddenMarkers=[])).push(this)}this.lines.push(a)};Ca.prototype.detachLine=function(a){if(this.lines.splice(N(this.lines,a),1),!this.lines.length&&this.doc.cm)a=this.doc.cm.curOp,(a.maybeHiddenMarkers||(a.maybeHiddenMarkers=[])).push(this)};ab(Ca);var Ob=function(a,b){this.markers=a;this.primary=b;for(var c=
+0;c<a.length;++c)a[c].parent=this};Ob.prototype.clear=function(){if(!this.explicitlyCleared){this.explicitlyCleared=!0;for(var a=0;a<this.markers.length;++a)this.markers[a].clear();P(this,"clear")}};Ob.prototype.find=function(a,b){return this.primary.find(a,b)};ab(Ob);var jh=0,W=function(a,b,c,d,e){if(!(this instanceof W))return new W(a,b,c,d,e);null==c&&(c=0);Mb.call(this,[new Lb([new hb("",null)])]);this.first=c;this.scrollTop=this.scrollLeft=0;this.cantEdit=!1;this.cleanGeneration=1;this.modeFrontier=
+this.highlightFrontier=c;c=m(c,0);this.sel=ua(c);this.history=new yc(null);this.id=++jh;this.modeOption=b;this.lineSep=d;this.direction="rtl"==e?"rtl":"ltr";this.extend=!1;"string"==typeof a&&(a=this.splitLines(a));Cd(this,{from:c,to:c,text:a});Q(this,ua(c),pa)};W.prototype=Rd(Mb.prototype,{constructor:W,iter:function(a,b,c){c?this.iterN(a-this.first,b-a,c):this.iterN(this.first,this.first+this.size,a)},insert:function(a,b){for(var c=0,d=0;d<b.length;++d)c+=b[d].height;this.insertInner(a-this.first,
+b,c)},remove:function(a,b){this.removeInner(a-this.first,b)},getValue:function(a){var b=Pc(this,this.first,this.first+this.size);return!1===a?b:b.join(a||this.lineSeparator())},setValue:M(function(a){var b=m(this.first,0),c=this.first+this.size-1;kb(this,{from:b,to:m(c,w(this,c).text.length),text:this.splitLines(a),origin:"setValue",full:!0},!0);this.cm&&Eb(this.cm,0,0);Q(this,ua(b),pa)}),replaceRange:function(a,b,c,d){b=v(this,b);c=c?v(this,c):b;lb(this,a,b,c,d)},getRange:function(a,b,c){a=Ga(this,
+v(this,a),v(this,b));return!1===c?a:a.join(c||this.lineSeparator())},getLine:function(a){return(a=this.getLineHandle(a))&&a.text},getLineHandle:function(a){if(sb(this,a))return w(this,a)},getLineNumber:function(a){return D(a)},getLineHandleVisualStart:function(a){return"number"==typeof a&&(a=w(this,a)),ma(a)},lineCount:function(){return this.size},firstLine:function(){return this.first},lastLine:function(){return this.first+this.size-1},clipPos:function(a){return v(this,a)},getCursor:function(a){var b=
+this.sel.primary();return null==a||"head"==a?b.head:"anchor"==a?b.anchor:"end"==a||"to"==a||!1===a?b.to():b.from()},listSelections:function(){return this.sel.ranges},somethingSelected:function(){return this.sel.somethingSelected()},setCursor:M(function(a,b,c){a=v(this,"number"==typeof a?m(a,b||0):a);Q(this,ua(a,null),c)}),setSelection:M(function(a,b,c){var d=v(this,a);a=v(this,b||a);Q(this,ua(d,a),c)}),extendSelection:M(function(a,b,c){Ac(this,v(this,a),b&&v(this,b),c)}),extendSelections:M(function(a,
+b){hf(this,Vd(this,a),b)}),extendSelectionsBy:M(function(a,b){hf(this,Vd(this,ec(this.sel.ranges,a)),b)}),setSelections:M(function(a,b,c){if(a.length){for(var d=[],e=0;e<a.length;e++)d[e]=new A(v(this,a[e].anchor),v(this,a[e].head));null==b&&(b=Math.min(a.length-1,this.sel.primIndex));Q(this,ka(d,b),c)}}),addSelection:M(function(a,b,c){var d=this.sel.ranges.slice(0);d.push(new A(v(this,a),v(this,b||a)));Q(this,ka(d,d.length-1),c)}),getSelection:function(a){for(var b,c=this.sel.ranges,d=0;d<c.length;d++){var e=
+Ga(this,c[d].from(),c[d].to());b=b?b.concat(e):e}return!1===a?b:b.join(a||this.lineSeparator())},getSelections:function(a){for(var b=[],c=this.sel.ranges,d=0;d<c.length;d++){var e=Ga(this,c[d].from(),c[d].to());!1!==a&&(e=e.join(a||this.lineSeparator()));b[d]=e}return b},replaceSelection:function(a,b,c){for(var d=[],e=0;e<this.sel.ranges.length;e++)d[e]=a;this.replaceSelections(d,b,c||"+input")},replaceSelections:M(function(a,b,c){for(var d=[],e=this.sel,f=0;f<e.ranges.length;f++){var g=e.ranges[f];
+d[f]={from:g.from(),to:g.to(),text:this.splitLines(a[f]),origin:c}}if(a=b&&"end"!=b){a=[];e=c=m(this.first,0);for(f=0;f<d.length;f++){var h=d[f],g=$e(h.from,c,e),k=$e(Ba(h),c,e);(c=h.to,e=k,"around"==b)?(h=this.sel.ranges[f],h=0>x(h.head,h.anchor),a[f]=new A(h?k:g,h?g:k)):a[f]=new A(g,g)}a=new ca(a,this.sel.primIndex)}b=a;for(a=d.length-1;0<=a;a--)kb(this,d[a]);b?jf(this,b):this.cm&&fb(this.cm)}),undo:M(function(){Cc(this,"undo")}),redo:M(function(){Cc(this,"redo")}),undoSelection:M(function(){Cc(this,
+"undo",!0)}),redoSelection:M(function(){Cc(this,"redo",!0)}),setExtending:function(a){this.extend=a},getExtending:function(){return this.extend},historySize:function(){for(var a=this.history,b=0,c=0,d=0;d<a.done.length;d++)a.done[d].ranges||++b;for(d=0;d<a.undone.length;d++)a.undone[d].ranges||++c;return{undo:b,redo:c}},clearHistory:function(){this.history=new yc(this.history.maxGeneration)},markClean:function(){this.cleanGeneration=this.changeGeneration(!0)},changeGeneration:function(a){return a&&
+(this.history.lastOp=this.history.lastSelOp=this.history.lastOrigin=null),this.history.generation},isClean:function(a){return this.history.generation==(a||this.cleanGeneration)},getHistory:function(){return{done:ib(this.history.done),undone:ib(this.history.undone)}},setHistory:function(a){var b=this.history=new yc(this.history.maxGeneration);b.done=ib(a.done.slice(0),null,!0);b.undone=ib(a.undone.slice(0),null,!0)},setGutterMarker:M(function(a,b,c){return Kb(this,a,"gutter",function(a){var e=a.gutterMarkers||
+(a.gutterMarkers={});return e[b]=c,!c&&Sd(e)&&(a.gutterMarkers=null),!0})}),clearGutter:M(function(a){var b=this;this.iter(function(c){c.gutterMarkers&&c.gutterMarkers[a]&&Kb(b,c,"gutter",function(){return c.gutterMarkers[a]=null,Sd(c.gutterMarkers)&&(c.gutterMarkers=null),!0})})}),lineInfo:function(a){var b;if("number"==typeof a){if(!(sb(this,a)&&(b=a,a=w(this,a))))return null}else if(null==(b=D(a)))return null;return{line:b,handle:a,text:a.text,gutterMarkers:a.gutterMarkers,textClass:a.textClass,
+bgClass:a.bgClass,wrapClass:a.wrapClass,widgets:a.widgets}},addLineClass:M(function(a,b,c){return Kb(this,a,"gutter"==b?"gutter":"class",function(a){var e="text"==b?"textClass":"background"==b?"bgClass":"gutter"==b?"gutterClass":"wrapClass";if(a[e]){if(ga(c).test(a[e]))return!1;a[e]+=" "+c}else a[e]=c;return!0})}),removeLineClass:M(function(a,b,c){return Kb(this,a,"gutter"==b?"gutter":"class",function(a){var e="text"==b?"textClass":"background"==b?"bgClass":"gutter"==b?"gutterClass":"wrapClass",f=
+a[e];if(!f)return!1;if(null==c)a[e]=null;else{var g=f.match(ga(c));if(!g)return!1;var h=g.index+g[0].length;a[e]=f.slice(0,g.index)+(g.index&&h!=f.length?" ":"")+f.slice(h)||null}return!0})}),addLineWidget:M(function(a,b,c){return Gg(this,a,b,c)}),removeLineWidget:function(a){a.clear()},markText:function(a,b,c){return mb(this,v(this,a),v(this,b),c,c&&c.type||"range")},setBookmark:function(a,b){var c={replacedWith:b&&(null==b.nodeType?b.widget:b),insertLeft:b&&b.insertLeft,clearWhenEmpty:!1,shared:b&&
+b.shared,handleMouseEvents:b&&b.handleMouseEvents};return a=v(this,a),mb(this,a,a,c,"bookmark")},findMarksAt:function(a){a=v(this,a);var b=[],c=w(this,a.line).markedSpans;if(c)for(var d=0;d<c.length;++d){var e=c[d];(null==e.from||e.from<=a.ch)&&(null==e.to||e.to>=a.ch)&&b.push(e.marker.parent||e.marker)}return b},findMarks:function(a,b,c){a=v(this,a);b=v(this,b);var d=[],e=a.line;return this.iter(a.line,b.line+1,function(f){if(f=f.markedSpans)for(var g=0;g<f.length;g++){var h=f[g];null!=h.to&&e==
+a.line&&a.ch>=h.to||null==h.from&&e!=a.line||null!=h.from&&e==b.line&&h.from>=b.ch||c&&!c(h.marker)||d.push(h.marker.parent||h.marker)}++e}),d},getAllMarks:function(){var a=[];return this.iter(function(b){if(b=b.markedSpans)for(var c=0;c<b.length;++c)null!=b[c].from&&a.push(b[c].marker)}),a},posFromIndex:function(a){var b,c=this.first,d=this.lineSeparator().length;return this.iter(function(e){e=e.text.length+d;if(e>a)return b=a,!0;a-=e;++c}),v(this,m(c,b))},indexFromPos:function(a){a=v(this,a);var b=
+a.ch;if(a.line<this.first||0>a.ch)return 0;var c=this.lineSeparator().length;return this.iter(this.first,a.line,function(a){b+=a.text.length+c}),b},copy:function(a){var b=new W(Pc(this,this.first,this.first+this.size),this.modeOption,this.first,this.lineSep,this.direction);return b.scrollTop=this.scrollTop,b.scrollLeft=this.scrollLeft,b.sel=this.sel,b.extend=!1,a&&(b.history.undoDepth=this.history.undoDepth,b.setHistory(this.getHistory())),b},linkedDoc:function(a){a||(a={});var b=this.first,c=this.first+
+this.size;null!=a.from&&a.from>b&&(b=a.from);null!=a.to&&a.to<c&&(c=a.to);b=new W(Pc(this,b,c),a.mode||this.modeOption,b,this.lineSep,this.direction);a.sharedHist&&(b.history=this.history);(this.linked||(this.linked=[])).push({doc:b,sharedHist:a.sharedHist});b.linked=[{doc:this,isParent:!0,sharedHist:a.sharedHist}];a=wf(this);for(c=0;c<a.length;c++){var d=a[c],e=d.find(),f=b.clipPos(e.from),e=b.clipPos(e.to);x(f,e)&&(f=mb(b,f,e,d.primary,d.primary.type),d.markers.push(f),f.parent=d)}return b},unlinkDoc:function(a){if(a instanceof
+E&&(a=a.doc),this.linked)for(var b=0;b<this.linked.length;++b)if(this.linked[b].doc==a){this.linked.splice(b,1);a.unlinkDoc(this);Ig(wf(this));break}if(a.history==this.history){var c=[a.id];Va(a,function(a){return c.push(a.id)},!0);a.history=new yc(null);a.history.done=ib(this.history.done,c);a.history.undone=ib(this.history.undone,c)}},iterLinkedDocs:function(a){Va(this,a)},getMode:function(){return this.mode},getEditor:function(){return this.cm},splitLines:function(a){return this.lineSep?a.split(this.lineSep):
+Od(a)},lineSeparator:function(){return this.lineSep||"\n"},setDirection:M(function(a){"rtl"!=a&&(a="ltr");a!=this.direction&&(this.direction=a,this.iter(function(a){return a.order=null}),this.cm&&Cg(this.cm))})});W.prototype.eachLine=W.prototype.iter;for(var yf=0,Pf=!1,Da={3:"Enter",8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"PrintScrn",45:"Insert",
+46:"Delete",59:";",61:"\x3d",91:"Mod",92:"Mod",93:"Mod",106:"*",107:"\x3d",109:"-",110:".",111:"/",127:"Delete",173:"-",186:";",187:"\x3d",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",63232:"Up",63233:"Down",63234:"Left",63235:"Right",63272:"Delete",63273:"Home",63275:"End",63276:"PageUp",63277:"PageDown",63302:"Insert"},ac=0;10>ac;ac++)Da[ac+48]=Da[ac+96]=String(ac);for(var Ic=65;90>=Ic;Ic++)Da[Ic]=String.fromCharCode(Ic);for(var bc=1;12>=bc;bc++)Da[bc+111]=Da[bc+63235]=
+"F"+bc;var Pb={basic:{Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},pcDefault:{"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart",
+"Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},
+emacsy:{"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Alt-F":"goWordRight","Alt-B":"goWordLeft","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-D":"delWordAfter","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},macDefault:{"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo",
+"Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight",
+"Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]}};Pb["default"]=ha?Pb.macDefault:Pb.pcDefault;var Qb={selectAll:of,singleSelection:function(a){return a.setSelection(a.getCursor("anchor"),a.getCursor("head"),pa)},killLine:function(a){return ob(a,function(b){if(b.empty()){var c=w(a.doc,b.head.line).text.length;return b.head.ch==c&&b.head.line<a.lastLine()?{from:b.head,to:m(b.head.line+1,0)}:{from:b.head,to:m(b.head.line,
+c)}}return{from:b.from(),to:b.to()}})},deleteLine:function(a){return ob(a,function(b){return{from:m(b.from().line,0),to:v(a.doc,m(b.to().line+1,0))}})},delLineLeft:function(a){return ob(a,function(a){return{from:m(a.from().line,0),to:a.from()}})},delWrappedLineLeft:function(a){return ob(a,function(b){var c=a.charCoords(b.head,"div").top+5;return{from:a.coordsChar({left:0,top:c},"div"),to:b.from()}})},delWrappedLineRight:function(a){return ob(a,function(b){var c=a.charCoords(b.head,"div").top+5,c=
+a.coordsChar({left:a.display.lineDiv.offsetWidth+100,top:c},"div");return{from:b.from(),to:c}})},undo:function(a){return a.undo()},redo:function(a){return a.redo()},undoSelection:function(a){return a.undoSelection()},redoSelection:function(a){return a.redoSelection()},goDocStart:function(a){return a.extendSelection(m(a.firstLine(),0))},goDocEnd:function(a){return a.extendSelection(m(a.lastLine()))},goLineStart:function(a){return a.extendSelectionsBy(function(b){return Ef(a,b.head.line)},{origin:"+move",
+bias:1})},goLineStartSmart:function(a){return a.extendSelectionsBy(function(b){return Ff(a,b.head)},{origin:"+move",bias:1})},goLineEnd:function(a){return a.extendSelectionsBy(function(b){b=b.head.line;var c=w(a.doc,b),d;d=c;for(var e;e=Ia(d,!1);)d=e.find(1,!0).line;return d!=c&&(b=D(d)),$c(!0,a,c,b,-1)},{origin:"+move",bias:-1})},goLineRight:function(a){return a.extendSelectionsBy(function(b){b=a.cursorCoords(b.head,"div").top+5;return a.coordsChar({left:a.display.lineDiv.offsetWidth+100,top:b},
+"div")},Zb)},goLineLeft:function(a){return a.extendSelectionsBy(function(b){b=a.cursorCoords(b.head,"div").top+5;return a.coordsChar({left:0,top:b},"div")},Zb)},goLineLeftSmart:function(a){return a.extendSelectionsBy(function(b){var c=a.cursorCoords(b.head,"div").top+5,c=a.coordsChar({left:0,top:c},"div");return c.ch<a.getLine(c.line).search(/\S/)?Ff(a,b.head):c},Zb)},goLineUp:function(a){return a.moveV(-1,"line")},goLineDown:function(a){return a.moveV(1,"line")},goPageUp:function(a){return a.moveV(-1,
+"page")},goPageDown:function(a){return a.moveV(1,"page")},goCharLeft:function(a){return a.moveH(-1,"char")},goCharRight:function(a){return a.moveH(1,"char")},goColumnLeft:function(a){return a.moveH(-1,"column")},goColumnRight:function(a){return a.moveH(1,"column")},goWordLeft:function(a){return a.moveH(-1,"word")},goGroupRight:function(a){return a.moveH(1,"group")},goGroupLeft:function(a){return a.moveH(-1,"group")},goWordRight:function(a){return a.moveH(1,"word")},delCharBefore:function(a){return a.deleteH(-1,
+"char")},delCharAfter:function(a){return a.deleteH(1,"char")},delWordBefore:function(a){return a.deleteH(-1,"word")},delWordAfter:function(a){return a.deleteH(1,"word")},delGroupBefore:function(a){return a.deleteH(-1,"group")},delGroupAfter:function(a){return a.deleteH(1,"group")},indentAuto:function(a){return a.indentSelection("smart")},indentMore:function(a){return a.indentSelection("add")},indentLess:function(a){return a.indentSelection("subtract")},insertTab:function(a){return a.replaceSelection("\t")},
+insertSoftTab:function(a){for(var b=[],c=a.listSelections(),d=a.options.tabSize,e=0;e<c.length;e++){var f=c[e].from(),f=ea(a.getLine(f.line),f.ch,d);b.push(Mc(d-f%d))}a.replaceSelections(b)},defaultTab:function(a){a.somethingSelected()?a.indentSelection("add"):a.execCommand("insertTab")},transposeChars:function(a){return Y(a,function(){for(var b=a.listSelections(),c=[],d=0;d<b.length;d++)if(b[d].empty()){var e=b[d].head,f=w(a.doc,e.line).text;if(f)if(e.ch==f.length&&(e=new m(e.line,e.ch-1)),0<e.ch)e=
+new m(e.line,e.ch+1),a.replaceRange(f.charAt(e.ch-1)+f.charAt(e.ch-2),m(e.line,e.ch-2),e,"+transpose");else if(e.line>a.doc.first){var g=w(a.doc,e.line-1).text;g&&(e=new m(e.line,1),a.replaceRange(f.charAt(0)+a.doc.lineSeparator()+g.charAt(g.length-1),m(e.line-1,g.length-1),e,"+transpose"))}c.push(new A(e,e))}a.setSelections(c)})},newlineAndIndent:function(a){return Y(a,function(){for(var b=a.listSelections(),c=b.length-1;0<=c;c--)a.replaceRange(a.doc.lineSeparator(),b[c].anchor,b[c].head,"+input");
+b=a.listSelections();for(c=0;c<b.length;c++)a.indentLine(b[c].from().line,null,!0);fb(a)})},openLine:function(a){return a.replaceSelection("\n","start")},toggleOverwrite:function(a){return a.toggleOverwrite()}},Pg=new Wa,Hd=null,Id=function(a,b,c){this.time=a;this.pos=b;this.button=c};Id.prototype.compare=function(a,b,c){return this.time+400>a&&0==x(b,this.pos)&&c==this.button};var Tb,Sb,pb={toString:function(){return"CodeMirror.Init"}},Of={},Gc={};E.defaults=Of;E.optionHandlers=Gc;var Md=[];E.defineInitHook=
+function(a){return Md.push(a)};var da=null,y=function(a){this.cm=a;this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null;this.polling=new Wa;this.composing=null;this.gracePeriod=!1;this.readDOMTimeout=null};y.prototype.init=function(a){function b(a){if(!K(e,a)){if(e.somethingSelected())Rf({lineWise:!1,text:e.getSelections()}),"cut"==a.type&&e.replaceSelection("",null,"cut");else{if(!e.options.lineWiseCopyCut)return;var b=Uf(e);Rf({lineWise:!0,text:b.text});"cut"==
+a.type&&e.operation(function(){e.setSelections(b.ranges,0,pa);e.replaceSelection("",null,"cut")})}if(a.clipboardData){a.clipboardData.clearData();var c=da.text.join("\n");if(a.clipboardData.setData("Text",c),a.clipboardData.getData("Text")==c)return void a.preventDefault()}var l=Wf();a=l.firstChild;e.display.lineSpace.insertBefore(l,e.display.lineSpace.firstChild);a.value=da.text.join("\n");var n=document.activeElement;Yb(a);setTimeout(function(){e.display.lineSpace.removeChild(l);n.focus();n==f&&
+d.showPrimarySelection()},50)}}var c=this,d=this,e=d.cm,f=d.div=a.lineDiv;Vf(f,e.options.spellcheck);t(f,"paste",function(a){K(e,a)||Tf(a,e)||11>=B&&setTimeout(L(e,function(){return c.updateFromDOM()}),20)});t(f,"compositionstart",function(a){c.composing={data:a.data,done:!1}});t(f,"compositionupdate",function(a){c.composing||(c.composing={data:a.data,done:!1})});t(f,"compositionend",function(a){c.composing&&(a.data!=c.composing.data&&c.readFromDOMSoon(),c.composing.done=!0)});t(f,"touchstart",function(){return d.forceCompositionEnd()});
+t(f,"input",function(){c.composing||c.readFromDOMSoon()});t(f,"copy",b);t(f,"cut",b)};y.prototype.prepareSelection=function(){var a=Ie(this.cm,!1);return a.focus=this.cm.state.focused,a};y.prototype.showSelection=function(a,b){a&&this.cm.display.view.length&&((a.focus||b)&&this.showPrimarySelection(),this.showMultipleSelections(a))};y.prototype.showPrimarySelection=function(){var a=window.getSelection(),b=this.cm,c=b.doc.sel.primary(),d=c.from(),c=c.to();if(b.display.viewTo==b.display.viewFrom||d.line>=
+b.display.viewTo||c.line<b.display.viewFrom)return void a.removeAllRanges();var e=Hc(b,a.anchorNode,a.anchorOffset),f=Hc(b,a.focusNode,a.focusOffset);if(!e||e.bad||!f||f.bad||0!=x(ic(e,f),d)||0!=x(hc(e,f),c)){e=b.display.view;d=d.line>=b.display.viewFrom&&Yf(b,d)||{node:e[0].measure.map[2],offset:0};c=c.line<b.display.viewTo&&Yf(b,c);c||(c=e[e.length-1].measure,c=c.maps?c.maps[c.maps.length-1]:c.map,c={node:c[c.length-1],offset:c[c.length-2]-c[c.length-3]});if(!d||!c)return void a.removeAllRanges();
+var g,e=a.rangeCount&&a.getRangeAt(0);try{g=db(d.node,d.offset,c.offset,c.node)}catch(h){}g&&(!wa&&b.state.focused?(a.collapse(d.node,d.offset),g.collapsed||(a.removeAllRanges(),a.addRange(g))):(a.removeAllRanges(),a.addRange(g)),e&&null==a.anchorNode?a.addRange(e):wa&&this.startGracePeriod());this.rememberSelection()}};y.prototype.startGracePeriod=function(){var a=this;clearTimeout(this.gracePeriod);this.gracePeriod=setTimeout(function(){a.gracePeriod=!1;a.selectionChanged()&&a.cm.operation(function(){return a.cm.curOp.selectionChanged=
+!0})},20)};y.prototype.showMultipleSelections=function(a){Z(this.cm.display.cursorDiv,a.cursors);Z(this.cm.display.selectionDiv,a.selection)};y.prototype.rememberSelection=function(){var a=window.getSelection();this.lastAnchorNode=a.anchorNode;this.lastAnchorOffset=a.anchorOffset;this.lastFocusNode=a.focusNode;this.lastFocusOffset=a.focusOffset};y.prototype.selectionInEditor=function(){var a=window.getSelection();if(!a.rangeCount)return!1;a=a.getRangeAt(0).commonAncestorContainer;return va(this.div,
+a)};y.prototype.focus=function(){"nocursor"!=this.cm.options.readOnly&&(this.selectionInEditor()||this.showSelection(this.prepareSelection(),!0),this.div.focus())};y.prototype.blur=function(){this.div.blur()};y.prototype.getField=function(){return this.div};y.prototype.supportsTouch=function(){return!0};y.prototype.receivedFocus=function(){function a(){b.cm.state.focused&&(b.pollSelection(),b.polling.set(b.cm.options.pollInterval,a))}var b=this;this.selectionInEditor()?this.pollSelection():Y(this.cm,
+function(){return b.cm.curOp.selectionChanged=!0});this.polling.set(this.cm.options.pollInterval,a)};y.prototype.selectionChanged=function(){var a=window.getSelection();return a.anchorNode!=this.lastAnchorNode||a.anchorOffset!=this.lastAnchorOffset||a.focusNode!=this.lastFocusNode||a.focusOffset!=this.lastFocusOffset};y.prototype.pollSelection=function(){if(null==this.readDOMTimeout&&!this.gracePeriod&&this.selectionChanged()){var a=window.getSelection(),b=this.cm;if(qc&&pc&&this.cm.options.gutters.length&&
+ch(a.anchorNode))return this.cm.triggerOnKeyDown({type:"keydown",keyCode:8,preventDefault:Math.abs}),this.blur(),void this.focus();if(!this.composing){this.rememberSelection();var c=Hc(b,a.anchorNode,a.anchorOffset),d=Hc(b,a.focusNode,a.focusOffset);c&&d&&Y(b,function(){Q(b.doc,ua(c,d),pa);(c.bad||d.bad)&&(b.curOp.selectionChanged=!0)})}}};y.prototype.pollContent=function(){null!=this.readDOMTimeout&&(clearTimeout(this.readDOMTimeout),this.readDOMTimeout=null);var a=this.cm,b=a.display,c=a.doc.sel.primary(),
+d=c.from(),c=c.to();if(0==d.ch&&d.line>a.firstLine()&&(d=m(d.line-1,w(a.doc,d.line-1).length)),c.ch==w(a.doc,c.line).text.length&&c.line<a.lastLine()&&(c=m(c.line+1,0)),d.line<b.viewFrom||c.line>b.viewTo-1)return!1;var e,f,g;d.line==b.viewFrom||0==(e=Na(a,d.line))?(f=D(b.view[0].line),g=b.view[0].node):(f=D(b.view[e].line),g=b.view[e-1].node.nextSibling);var h,k;e=Na(a,c.line);if(e==b.view.length-1?(h=b.viewTo-1,k=b.lineDiv.lastChild):(h=D(b.view[e+1].line)-1,k=b.view[e+1].node.previousSibling),!g)return!1;
+b=a.doc.splitLines(dh(a,g,k,f,h));for(g=Ga(a.doc,m(f,0),m(h,w(a.doc,h).text.length));1<b.length&&1<g.length;)if(z(b)==z(g))b.pop(),g.pop(),h--;else{if(b[0]!=g[0])break;b.shift();g.shift();f++}k=e=0;for(var c=b[0],l=g[0],n=Math.min(c.length,l.length);e<n&&c.charCodeAt(e)==l.charCodeAt(e);)++e;c=z(b);l=z(g);for(n=Math.min(c.length-(1==b.length?e:0),l.length-(1==g.length?e:0));k<n&&c.charCodeAt(c.length-k-1)==l.charCodeAt(l.length-k-1);)++k;if(1==b.length&&1==g.length&&f==d.line)for(;e&&e>d.ch&&c.charCodeAt(c.length-
+k-1)==l.charCodeAt(l.length-k-1);)e--,k++;b[b.length-1]=c.slice(0,c.length-k).replace(/^\u200b+/,"");b[0]=b[0].slice(e).replace(/\u200b+$/,"");d=m(f,e);h=m(h,g.length?z(g).length-k:0);return 1<b.length||b[0]||x(d,h)?(lb(a.doc,b,d,h,"+input"),!0):void 0};y.prototype.ensurePolled=function(){this.forceCompositionEnd()};y.prototype.reset=function(){this.forceCompositionEnd()};y.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),
+this.div.blur(),this.div.focus())};y.prototype.readFromDOMSoon=function(){var a=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout(function(){if(a.readDOMTimeout=null,a.composing){if(!a.composing.done)return;a.composing=null}a.updateFromDOM()},80))};y.prototype.updateFromDOM=function(){var a=this;!this.cm.isReadOnly()&&this.pollContent()||Y(this.cm,function(){return V(a.cm)})};y.prototype.setUneditable=function(a){a.contentEditable="false"};y.prototype.onKeyPress=function(a){0!=a.charCode&&
+(a.preventDefault(),this.cm.isReadOnly()||L(this.cm,Nd)(this.cm,String.fromCharCode(null==a.charCode?a.keyCode:a.charCode),0))};y.prototype.readOnlyChanged=function(a){this.div.contentEditable=String("nocursor"!=a)};y.prototype.onContextMenu=function(){};y.prototype.resetPosition=function(){};y.prototype.needsContentAttribute=!0;var I=function(a){this.cm=a;this.prevInput="";this.pollingFast=!1;this.polling=new Wa;this.hasSelection=!1;this.composing=null};I.prototype.init=function(a){function b(a){if(!K(e,
+a)){if(e.somethingSelected())da={lineWise:!1,text:e.getSelections()};else{if(!e.options.lineWiseCopyCut)return;var b=Uf(e);da={lineWise:!0,text:b.text};"cut"==a.type?e.setSelections(b.ranges,null,pa):(d.prevInput="",g.value=b.text.join("\n"),Yb(g))}"cut"==a.type&&(e.state.cutIncoming=!0)}}var c=this,d=this,e=this.cm,f=this.wrapper=Wf(),g=this.textarea=f.firstChild;a.wrapper.insertBefore(f,a.wrapper.firstChild);Wb&&(g.style.width="0px");t(g,"input",function(){C&&9<=B&&c.hasSelection&&(c.hasSelection=
+null);d.poll()});t(g,"paste",function(a){K(e,a)||Tf(a,e)||(e.state.pasteIncoming=!0,d.fastPoll())});t(g,"cut",b);t(g,"copy",b);t(a.scroller,"paste",function(b){ta(a,b)||K(e,b)||(e.state.pasteIncoming=!0,d.focus())});t(a.lineSpace,"selectstart",function(b){ta(a,b)||S(b)});t(g,"compositionstart",function(){var a=e.getCursor("from");d.composing&&d.composing.range.clear();d.composing={start:a,range:e.markText(a,e.getCursor("to"),{className:"CodeMirror-composing"})}});t(g,"compositionend",function(){d.composing&&
+(d.poll(),d.composing.range.clear(),d.composing=null)})};I.prototype.prepareSelection=function(){var a=this.cm,b=a.display,c=a.doc,d=Ie(a);if(a.options.moveInputWithCursor){var a=ia(a,c.sel.primary().head,"div"),c=b.wrapper.getBoundingClientRect(),e=b.lineDiv.getBoundingClientRect();d.teTop=Math.max(0,Math.min(b.wrapper.clientHeight-10,a.top+e.top-c.top));d.teLeft=Math.max(0,Math.min(b.wrapper.clientWidth-10,a.left+e.left-c.left))}return d};I.prototype.showSelection=function(a){var b=this.cm.display;
+Z(b.cursorDiv,a.cursors);Z(b.selectionDiv,a.selection);null!=a.teTop&&(this.wrapper.style.top=a.teTop+"px",this.wrapper.style.left=a.teLeft+"px")};I.prototype.reset=function(a){if(!this.contextMenuPending&&!this.composing){var b=this.cm;b.somethingSelected()?(this.prevInput="",a=b.getSelection(),this.textarea.value=a,b.state.focused&&Yb(this.textarea),C&&9<=B&&(this.hasSelection=a)):a||(this.prevInput=this.textarea.value="",C&&9<=B&&(this.hasSelection=null))}};I.prototype.getField=function(){return this.textarea};
+I.prototype.supportsTouch=function(){return!1};I.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!rb||qa()!=this.textarea))try{this.textarea.focus()}catch(a){}};I.prototype.blur=function(){this.textarea.blur()};I.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0};I.prototype.receivedFocus=function(){this.slowPoll()};I.prototype.slowPoll=function(){var a=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){a.poll();a.cm.state.focused&&
+a.slowPoll()})};I.prototype.fastPoll=function(){function a(){c.poll()||b?(c.pollingFast=!1,c.slowPoll()):(b=!0,c.polling.set(60,a))}var b=!1,c=this;c.pollingFast=!0;c.polling.set(20,a)};I.prototype.poll=function(){var a=this,b=this.cm,c=this.textarea,d=this.prevInput;if(this.contextMenuPending||!b.state.focused||ih(c)&&!d&&!this.composing||b.isReadOnly()||b.options.disableInput||b.state.keySeq)return!1;var e=c.value;if(e==d&&!b.somethingSelected())return!1;if(C&&9<=B&&this.hasSelection===e||ha&&/[\uf700-\uf7ff]/.test(e))return b.display.input.reset(),
+!1;if(b.doc.sel==b.display.selForContextMenu){var f=e.charCodeAt(0);if(8203!=f||d||(d="​"),8666==f)return this.reset(),this.cm.execCommand("undo")}for(var g=0,f=Math.min(d.length,e.length);g<f&&d.charCodeAt(g)==e.charCodeAt(g);)++g;return Y(b,function(){Nd(b,e.slice(g),d.length-g,null,a.composing?"*compose":null);1E3<e.length||-1<e.indexOf("\n")?c.value=a.prevInput="":a.prevInput=e;a.composing&&(a.composing.range.clear(),a.composing.range=b.markText(a.composing.start,b.getCursor("to"),{className:"CodeMirror-composing"}))}),
+!0};I.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)};I.prototype.onKeyPress=function(){C&&9<=B&&(this.hasSelection=null);this.fastPoll()};I.prototype.onContextMenu=function(a){function b(){if(null!=g.selectionStart){var a=e.somethingSelected(),b="​"+(a?g.value:"");g.value="⇚";g.value=b;d.prevInput=a?"":"​";g.selectionStart=1;g.selectionEnd=b.length;f.selForContextMenu=e.doc.sel}}function c(){if(d.contextMenuPending=!1,d.wrapper.style.cssText=n,g.style.cssText=
+l,C&&9>B&&f.scrollbars.setScrollTop(f.scroller.scrollTop=k),null!=g.selectionStart){(!C||C&&9>B)&&b();var a=0,c=function(){f.selForContextMenu==e.doc.sel&&0==g.selectionStart&&0<g.selectionEnd&&"​"==d.prevInput?L(e,of)(e):10>a++?f.detectingSelectAll=setTimeout(c,500):(f.selForContextMenu=null,f.input.reset())};f.detectingSelectAll=setTimeout(c,200)}}var d=this,e=d.cm,f=e.display,g=d.textarea,h=Qa(e,a),k=f.scroller.scrollTop;if(h&&!ja){e.options.resetSelectionOnContextMenu&&-1==e.doc.sel.contains(h)&&
+L(e,Q)(e.doc,ua(h),pa);var l=g.style.cssText,n=d.wrapper.style.cssText;d.wrapper.style.cssText="position: absolute";h=d.wrapper.getBoundingClientRect();g.style.cssText="position: absolute; width: 30px; height: 30px;\n      top: "+(a.clientY-h.top-5)+"px; left: "+(a.clientX-h.left-5)+"px;\n      z-index: 1000; background: "+(C?"rgba(255, 255, 255, .05)":"transparent")+";\n      outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity\x3d5);";var m;if(R&&
+(m=window.scrollY),f.input.focus(),R&&window.scrollTo(null,m),f.input.reset(),e.somethingSelected()||(g.value=d.prevInput=" "),d.contextMenuPending=!0,f.selForContextMenu=e.doc.sel,clearTimeout(f.detectingSelectAll),C&&9<=B&&b(),Kd){vb(a);var p=function(){aa(window,"mouseup",p);setTimeout(c,20)};t(window,"mouseup",p)}else setTimeout(c,50)}};I.prototype.readOnlyChanged=function(a){a||this.reset();this.textarea.disabled="nocursor"==a};I.prototype.setUneditable=function(){};I.prototype.needsContentAttribute=
+!1;(function(a){function b(b,e,f,g){a.defaults[b]=e;f&&(c[b]=g?function(a,b,c){c!=pb&&f(a,b,c)}:f)}var c=a.optionHandlers;a.defineOption=b;a.Init=pb;b("value","",function(a,b){return a.setValue(b)},!0);b("mode",null,function(a,b){a.doc.modeOption=b;Bd(a)},!0);b("indentUnit",2,Bd,!0);b("indentWithTabs",!1);b("smartIndent",!0);b("tabSize",4,function(a){Ib(a);Bb(a);V(a)},!0);b("lineSeparator",null,function(a,b){if(a.doc.lineSep=b,b){var c=[],g=a.doc.first;a.doc.iter(function(a){for(var d=0;;){var h=
+a.text.indexOf(b,d);if(-1==h)break;d=h+b.length;c.push(m(g,h))}g++});for(var h=c.length-1;0<=h;h--)lb(a.doc,b,c[h],m(c[h].line,c[h].ch+b.length))}});b("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g,function(a,b,c){a.state.specialChars=new RegExp(b.source+(b.test("\t")?"":"|\t"),"g");c!=pb&&a.refresh()});b("specialCharPlaceholder",rg,function(a){return a.refresh()},!0);b("electricChars",!0);b("inputStyle",rb?"contenteditable":"textarea",function(){throw Error("inputStyle can not (yet) be changed in a running editor");
+},!0);b("spellcheck",!1,function(a,b){return a.getInputField().spellcheck=b},!0);b("rtlMoveVisually",!hh);b("wholeLineUpdateBefore",!0);b("theme","default",function(a){Nf(a);Ub(a)},!0);b("keyMap","default",function(a,b,c){b=Dc(b);(c=c!=pb&&Dc(c))&&c.detach&&c.detach(a,b);b.attach&&b.attach(a,c||null)});b("extraKeys",null);b("configureMouse",null);b("lineWrapping",!1,ah,!0);b("gutters",[],function(a){zd(a.options);Ub(a)},!0);b("fixedGutter",!0,function(a,b){a.display.gutters.style.left=b?pd(a.display)+
+"px":"0";a.refresh()},!0);b("coverGutterNextToScrollbar",!1,function(a){return gb(a)},!0);b("scrollbarStyle","native",function(a){Se(a);gb(a);a.display.scrollbars.setScrollTop(a.doc.scrollTop);a.display.scrollbars.setScrollLeft(a.doc.scrollLeft)},!0);b("lineNumbers",!1,function(a){zd(a.options);Ub(a)},!0);b("firstLineNumber",1,Ub,!0);b("lineNumberFormatter",function(a){return a},Ub,!0);b("showCursorWhenSelecting",!1,Cb,!0);b("resetSelectionOnContextMenu",!0);b("lineWiseCopyCut",!0);b("pasteLinesPerSelection",
+!0);b("readOnly",!1,function(a,b){"nocursor"==b&&(Db(a),a.display.input.blur());a.display.input.readOnlyChanged(b)});b("disableInput",!1,function(a,b){b||a.display.input.reset()},!0);b("dragDrop",!0,$g);b("allowDropFileTypes",null);b("cursorBlinkRate",530);b("cursorScrollMargin",0);b("cursorHeight",1,Cb,!0);b("singleCursorHeightPerLine",!0,Cb,!0);b("workTime",100);b("workDelay",100);b("flattenSpans",!0,Ib,!0);b("addModeClass",!1,Ib,!0);b("pollInterval",100);b("undoDepth",200,function(a,b){return a.doc.history.undoDepth=
+b});b("historyEventDelay",1250);b("viewportMargin",10,function(a){return a.refresh()},!0);b("maxHighlightLength",1E4,Ib,!0);b("moveInputWithCursor",!0,function(a,b){b||a.display.input.resetPosition()});b("tabindex",null,function(a,b){return a.display.input.getField().tabIndex=b||""});b("autofocus",null);b("direction","ltr",function(a,b){return a.doc.setDirection(b)},!0)})(E);(function(a){var b=a.optionHandlers,c=a.helpers={};a.prototype={constructor:a,focus:function(){window.focus();this.display.input.focus()},
+setOption:function(a,c){var f=this.options,g=f[a];f[a]==c&&"mode"!=a||(f[a]=c,b.hasOwnProperty(a)&&L(this,b[a])(this,c,g),F(this,"optionChange",this,a))},getOption:function(a){return this.options[a]},getDoc:function(){return this.doc},addKeyMap:function(a,b){this.state.keyMaps[b?"push":"unshift"](Dc(a))},removeKeyMap:function(a){for(var b=this.state.keyMaps,c=0;c<b.length;++c)if(b[c]==a||b[c].name==a)return b.splice(c,1),!0},addOverlay:T(function(b,c){var f=b.token?b:a.getMode(this.options,b);if(f.startState)throw Error("Overlays may not be stateful.");
+bg(this.state.overlays,{mode:f,modeSpec:b,opaque:c&&c.opaque,priority:c&&c.priority||0},function(a){return a.priority});this.state.modeGen++;V(this)}),removeOverlay:T(function(a){for(var b=this.state.overlays,c=0;c<b.length;++c){var g=b[c].modeSpec;if(g==a||"string"==typeof a&&g.name==a)return b.splice(c,1),this.state.modeGen++,void V(this)}}),indentLine:T(function(a,b,c){"string"!=typeof b&&"number"!=typeof b&&(b=null==b?this.options.smartIndent?"smart":"prev":b?"add":"subtract");sb(this.doc,a)&&
+Vb(this,a,b,c)}),indentSelection:T(function(a){for(var b=this.doc.sel.ranges,c=-1,g=0;g<b.length;g++){var h=b[g];if(h.empty())h.head.line>c&&(Vb(this,h.head.line,a,!0),c=h.head.line,g==this.doc.sel.primIndex&&fb(this));else{for(var k=h.from(),h=h.to(),l=Math.max(c,k.line),c=Math.min(this.lastLine(),h.line-(h.ch?0:1))+1,h=l;h<c;++h)Vb(this,h,a);h=this.doc.sel.ranges;0==k.ch&&b.length==h.length&&0<h[g].from().ch&&Fd(this.doc,g,new A(k,h[g].to()),pa)}}}),getTokenAt:function(a,b){return le(this,a,b)},
+getLineTokens:function(a,b){return le(this,m(a),b,!0)},getTokenTypeAt:function(a){a=v(this.doc,a);var b;b=je(this,w(this.doc,a.line));var c=0,g=(b.length-1)/2;a=a.ch;if(0==a)b=b[2];else for(;;){var h=c+g>>1;if((h?b[2*h-1]:0)>=a)g=h;else{if(!(b[2*h+1]<a)){b=b[2*h+2];break}c=h+1}}c=b?b.indexOf("overlay "):-1;return 0>c?b:0==c?null:b.slice(0,c-1)},getModeAt:function(b){var c=this.doc.mode;return c.innerMode?a.innerMode(c,this.getTokenAt(b).state).mode:c},getHelper:function(a,b){return this.getHelpers(a,
+b)[0]},getHelpers:function(a,b){var f=[];if(!c.hasOwnProperty(b))return f;var g=c[b],h=this.getModeAt(a);if("string"==typeof h[b])g[h[b]]&&f.push(g[h[b]]);else if(h[b])for(var k=0;k<h[b].length;k++){var l=g[h[b][k]];l&&f.push(l)}else h.helperType&&g[h.helperType]?f.push(g[h.helperType]):g[h.name]&&f.push(g[h.name]);for(k=0;k<g._global.length;k++)l=g._global[k],l.pred(h,this)&&-1==N(f,l.val)&&f.push(l.val);return f},getStateAfter:function(a,b){var c=this.doc;return a=Math.max(c.first,Math.min(null==
+a?c.first+c.size-1:a,c.first+c.size-1)),wb(this,a+1,b).state},cursorCoords:function(a,b){var c,g=this.doc.sel.primary();return c=null==a?g.head:"object"==typeof a?v(this.doc,a):a?g.from():g.to(),ia(this,c,b||"page")},charCoords:function(a,b){return rc(this,v(this.doc,a),b||"page")},coordsChar:function(a,b){return a=Fe(this,a,b||"page"),od(this,a.left,a.top)},lineAtHeight:function(a,b){return a=Fe(this,{top:a,left:0},b||"page").top,Ha(this.doc,a+this.display.viewOffset)},heightAtLine:function(a,b,
+c){var g=!1;if("number"==typeof a){var h=this.doc.first+this.doc.size-1;a<this.doc.first?a=this.doc.first:a>h&&(a=h,g=!0);a=w(this.doc,a)}return Ka(this,a,{top:0,left:0},b||"page",c||g).top+(g?this.doc.height-na(a):0)},defaultTextHeight:function(){return Oa(this.display)},defaultCharWidth:function(){return Ab(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(a,b,c,g,h){var k=this.display;a=ia(this,v(this.doc,a));var l=a.bottom,n=a.left;
+if(b.style.position="absolute",b.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(b),k.sizer.appendChild(b),"over"==g)l=a.top;else if("above"==g||"near"==g){var m=Math.max(k.wrapper.clientHeight,this.doc.height),p=Math.max(k.sizer.clientWidth,k.lineSpace.clientWidth);("above"==g||a.bottom+b.offsetHeight>m)&&a.top>b.offsetHeight?l=a.top-b.offsetHeight:a.bottom+b.offsetHeight<=m&&(l=a.bottom);n+b.offsetWidth>p&&(n=p-b.offsetWidth)}b.style.top=l+"px";b.style.left=b.style.right=
+"";"right"==h?(n=k.sizer.clientWidth-b.offsetWidth,b.style.right="0px"):("left"==h?n=0:"middle"==h&&(n=(k.sizer.clientWidth-b.offsetWidth)/2),b.style.left=n+"px");c&&(a=vd(this,{left:n,top:l,right:n+b.offsetWidth,bottom:l+b.offsetHeight}),null!=a.scrollTop&&Fb(this,a.scrollTop),null!=a.scrollLeft&&Sa(this,a.scrollLeft))},triggerOnKeyDown:T(Hf),triggerOnKeyPress:T(Jf),triggerOnKeyUp:If,triggerOnMouseDown:T(Kf),execCommand:function(a){if(Qb.hasOwnProperty(a))return Qb[a].call(null,this)},triggerElectric:T(function(a){Sf(this,
+a)}),findPosH:function(a,b,c,g){var h=1;0>b&&(h=-1,b=-b);a=v(this.doc,a);for(var k=0;k<b&&(a=Pd(this.doc,a,h,c,g),!a.hitSide);++k);return a},moveH:T(function(a,b){var c=this;this.extendSelectionsBy(function(g){return c.display.shift||c.doc.extend||g.empty()?Pd(c.doc,g.head,a,b,c.options.rtlMoveVisually):0>a?g.from():g.to()},Zb)}),deleteH:T(function(a,b){var c=this.doc;this.doc.sel.somethingSelected()?c.replaceSelection("",null,"+delete"):ob(this,function(g){var h=Pd(c,g.head,a,b,!1);return 0>a?{from:h,
+to:g.head}:{from:g.head,to:h}})}),findPosV:function(a,b,c,g){var h=1;0>b&&(h=-1,b=-b);a=v(this.doc,a);for(var k=0;k<b;++k){var l=ia(this,a,"div");if(null==g?g=l.left:l.left=g,a=Xf(this,l,h,c),a.hitSide)break}return a},moveV:T(function(a,b){var c=this,g=this.doc,h=[],k=!this.display.shift&&!g.extend&&g.sel.somethingSelected();if(g.extendSelectionsBy(function(l){if(k)return 0>a?l.from():l.to();var m=ia(c,l.head,"div");null!=l.goalColumn&&(m.left=l.goalColumn);h.push(m.left);var p=Xf(c,m,a,b);return"page"==
+b&&l==g.sel.primary()&&tc(c,rc(c,p,"div").top-m.top),p},Zb),h.length)for(var l=0;l<g.sel.ranges.length;l++)g.sel.ranges[l].goalColumn=h[l]}),findWordAt:function(a){var b=w(this.doc,a.line).text,c=a.ch,g=a.ch;if(b){var h=this.getHelper(a,"wordChars");"before"!=a.sticky&&g!=b.length||!c?++g:--c;for(var k=b.charAt(c),k=fc(k,h)?function(a){return fc(a,h)}:/\s/.test(k)?function(a){return/\s/.test(a)}:function(a){return!/\s/.test(a)&&!fc(a)};0<c&&k(b.charAt(c-1));)--c;for(;g<b.length&&k(b.charAt(g));)++g}return new A(m(a.line,
+c),m(a.line,g))},toggleOverwrite:function(a){null!=a&&a==this.state.overwrite||((this.state.overwrite=!this.state.overwrite)?Ea(this.display.cursorDiv,"CodeMirror-overwrite"):Ra(this.display.cursorDiv,"CodeMirror-overwrite"),F(this,"overwriteToggle",this,this.state.overwrite))},hasFocus:function(){return this.display.input.getField()==qa()},isReadOnly:function(){return!(!this.options.readOnly&&!this.doc.cantEdit)},scrollTo:T(function(a,b){Eb(this,a,b)}),getScrollInfo:function(){var a=this.display.scroller;
+return{left:a.scrollLeft,top:a.scrollTop,height:a.scrollHeight-oa(this)-this.display.barHeight,width:a.scrollWidth-oa(this)-this.display.barWidth,clientHeight:kd(this),clientWidth:Ma(this)}},scrollIntoView:T(function(a,b){null==a?(a={from:this.doc.sel.primary().head,to:null},null==b&&(b=this.options.cursorScrollMargin)):"number"==typeof a?a={from:m(a,0),to:null}:null==a.from&&(a={from:a,to:null});a.to||(a.to=a.from);a.margin=b||0;if(null!=a.from.line){var c=a;uc(this);this.curOp.scrollToPos=c}else Pe(this,
+a.from,a.to,a.margin)}),setSize:T(function(a,b){var c=this,g=function(a){return"number"==typeof a||/^\d+$/.test(String(a))?a+"px":a};null!=a&&(this.display.wrapper.style.width=g(a));null!=b&&(this.display.wrapper.style.height=g(b));this.options.lineWrapping&&Ce(this);var h=this.display.viewFrom;this.doc.iter(h,this.display.viewTo,function(a){if(a.widgets)for(var b=0;b<a.widgets.length;b++)if(a.widgets[b].noHScroll){Aa(c,h,"widget");break}++h});this.curOp.forceUpdate=!0;F(this,"refresh",this)}),operation:function(a){return Y(this,
+a)},startOperation:function(){return Ta(this)},endOperation:function(){return Ua(this)},refresh:T(function(){var a=this.display.cachedTextHeight;V(this);this.curOp.forceUpdate=!0;Bb(this);Eb(this,this.doc.scrollLeft,this.doc.scrollTop);ud(this);(null==a||.5<Math.abs(a-Oa(this.display)))&&qd(this);F(this,"refresh",this)}),swapDoc:T(function(a){var b=this.doc;return b.cm=null,bf(this,a),Bb(this),this.display.input.reset(),Eb(this,a.scrollLeft,a.scrollTop),this.curOp.forceScroll=!0,P(this,"swapDoc",
+this,b),b}),getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}};ab(a);a.registerHelper=function(b,e,f){c.hasOwnProperty(b)||(c[b]=a[b]={_global:[]});c[b][e]=f};a.registerGlobalHelper=function(b,e,f,g){a.registerHelper(b,e,g);c[b]._global.push({pred:f,val:g})}})(E);var kh="iter insert remove copy getEditor constructor".split(" "),
+cc;for(cc in W.prototype)W.prototype.hasOwnProperty(cc)&&0>N(kh,cc)&&(E.prototype[cc]=function(a){return function(){return a.apply(this.doc,arguments)}}(W.prototype[cc]));return ab(W),E.inputStyles={textarea:I,contenteditable:y},E.defineMode=function(a){E.defaults.mode||"null"==a||(E.defaults.mode=a);jg.apply(this,arguments)},E.defineMIME=function(a,b){bb[a]=b},E.defineMode("null",function(){return{token:function(a){return a.skipToEnd()}}}),E.defineMIME("text/plain","null"),E.defineExtension=function(a,
+b){E.prototype[a]=b},E.defineDocExtension=function(a,b){W.prototype[a]=b},E.fromTextArea=function(a,b){function c(){a.value=k.getValue()}if(b=b?Fa(b):{},b.value=a.value,!b.tabindex&&a.tabIndex&&(b.tabindex=a.tabIndex),!b.placeholder&&a.placeholder&&(b.placeholder=a.placeholder),null==b.autofocus){var d=qa();b.autofocus=d==a||null!=a.getAttribute("autofocus")&&d==document.body}var e;if(a.form&&(t(a.form,"submit",c),!b.leaveSubmitMethodAlone)){var f=a.form;e=f.submit;try{var g=f.submit=function(){c();
+f.submit=e;f.submit();f.submit=g}}catch(h){}}b.finishInit=function(b){b.save=c;b.getTextArea=function(){return a};b.toTextArea=function(){b.toTextArea=isNaN;c();a.parentNode.removeChild(b.getWrapperElement());a.style.display="";a.form&&(aa(a.form,"submit",c),"function"==typeof a.form.submit&&(a.form.submit=e))}};a.style.display="none";var k=E(function(b){return a.parentNode.insertBefore(b,a.nextSibling)},b);return k},function(a){a.off=aa;a.on=t;a.wheelEventPixels=Bg;a.Doc=W;a.splitLines=Od;a.countColumn=
+ea;a.findColumn=Lc;a.isWordChar=Nc;a.Pass=Fc;a.signal=F;a.Line=hb;a.changeEnd=Ba;a.scrollbarModel=Te;a.Pos=m;a.cmpPos=x;a.modes=cd;a.mimeModes=bb;a.resolveMode=mc;a.getMode=dd;a.modeExtensions=cb;a.extendMode=kg;a.copyState=La;a.startState=ge;a.innerMode=ed;a.commands=Qb;a.keyMap=Pb;a.keyName=Df;a.isModifierKey=Af;a.lookupKey=nb;a.normalizeKeyMap=Ng;a.StringStream=H;a.SharedTextMarker=Ob;a.TextMarker=Ca;a.LineWidget=Nb;a.e_preventDefault=S;a.e_stopPropagation=ee;a.e_stop=vb;a.addClass=Ea;a.contains=
+va;a.rmClass=Ra;a.keyNames=Da}(E),E.version="5.28.0",E});(function(ga){"function"==typeof ga.define&&ga.define("core",["codemirror.js"],function(X){ga.CodeMirror=X})})(this);
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/js/codemirror.mode.bbcode.min.js b/js/ckeditor/plugins/codemirror/js/codemirror.mode.bbcode.min.js
new file mode 100644 (file)
index 0000000..b881206
--- /dev/null
@@ -0,0 +1,4 @@
+CodeMirror.defineMode("bbcode",function(h){var k,l,m;k="b i u s img quote code list table  tr td size color url";l="* :-) hr cut";h.hasOwnProperty("bbCodeTags")&&(k=h.bbCodeTags);h.hasOwnProperty("bbCodeUnaryTags")&&(l=h.bbCodeUnaryTags);var c={cont:function(a,b){m=b;return a},escapeRegEx:function(a){return a.replace(/([\:\-\)\(\*\+\?\[\]])/g,"\\$1")}},n=/[a-zA-Z0-9_]/,p=/['"]/,q=new RegExp("(?:"+c.escapeRegEx(k).split(" ").join("|")+")"),r=new RegExp("(?:"+c.escapeRegEx(l).split(" ").join("|")+")"),
+f={tokenizer:function(a,b){if(a.eatSpace())return null;if(a.match("[",!0))return b.tokenize=f.bbcode,c.cont("tag","startTag");a.next();return null},inAttribute:function(a){return function(b,c){for(var d=null,g=null;!b.eol();){g=b.peek();if(b.next()==a&&"\\"!==d){c.tokenize=f.bbcode;break}d=g}return"string"}},bbcode:function(a,b){if(a.match("]",!0))return b.tokenize=f.tokenizer,c.cont("tag",null);if(a.match("[",!0))return c.cont("tag","startTag");var e=a.next();if(p.test(e))return b.tokenize=f.inAttribute(e),
+c.cont("string","string");if(/\d/.test(e))return a.eatWhile(/\d/),c.cont("number","number");if("whitespace"==b.last)return a.eatWhile(n),c.cont("attribute","modifier");if("property"==b.last)return a.eatWhile(n),c.cont("property",null);if(/\s/.test(e))return m="whitespace",null;var d="";"/"!=e&&(d+=e);for(var g=null;g=a.eat(n);)d+=g;return r.test(d)?c.cont("atom","atom"):q.test(d)?c.cont("keyword","keyword"):/\s/.test(e)?null:c.cont("tag","tag")}};return{startState:function(){return{tokenize:f.tokenizer,
+mode:"bbcode",last:null}},token:function(a,b){var c=b.tokenize(a,b);b.last=m;return c},electricChars:""}});CodeMirror.defineMIME("text/x-bbcode","bbcode");
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/js/codemirror.mode.bbcodemixed.min.js b/js/ckeditor/plugins/codemirror/js/codemirror.mode.bbcodemixed.min.js
new file mode 100644 (file)
index 0000000..4234575
--- /dev/null
@@ -0,0 +1,76 @@
+(function(g){"object"==typeof exports&&"object"==typeof module?g(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],g):g(CodeMirror)})(function(g){var z={autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,
+dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0,
+caseFold:!0},C={autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1,caseFold:!1};g.defineMode("xml",function(r,n){function B(a,f){function d(d){f.tokenize=d;return d(a,f)}var c=a.next();if("\x3c"==c){if(a.eat("!"))return a.eat("[")?a.match("CDATA[")?d(A("atom","]]\x3e")):null:a.match("--")?d(A("comment","--\x3e")):a.match("DOCTYPE",!0,!0)?(a.eatWhile(/[\w\._\-]/),d(H(1))):null;if(a.eat("?"))return a.eatWhile(/[\w\._\-]/),f.tokenize=A("meta","?\x3e"),
+"meta";M=a.eat("/")?"closeTag":"openTag";f.tokenize=G;return"tag bracket"}if("\x26"==c)return(a.eat("#")?a.eat("x")?a.eatWhile(/[a-fA-F\d]/)&&a.eat(";"):a.eatWhile(/[\d]/)&&a.eat(";"):a.eatWhile(/[\w\.\-:]/)&&a.eat(";"))?"atom":"error";a.eatWhile(/[^&<]/);return null}function G(a,f){var d=a.next();if("\x3e"==d||"/"==d&&a.eat("\x3e"))return f.tokenize=B,M="\x3e"==d?"endTag":"selfcloseTag","tag bracket";if("\x3d"==d)return M="equals",null;if("\x3c"==d)return f.tokenize=B,f.state=c,f.tagName=f.tagStart=
+null,(d=f.tokenize(a,f))?d+" tag error":"tag error";if(/[\'\"]/.test(d))return f.tokenize=J(d),f.stringStartCol=a.column(),f.tokenize(a,f);a.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);return"word"}function J(a){var f=function(d,f){for(;!d.eol();)if(d.next()==a){f.tokenize=G;break}return"string"};f.isInAttribute=!0;return f}function A(a,f){return function(d,c){for(;!d.eol();){if(d.match(f)){c.tokenize=B;break}d.next()}return a}}function H(a){return function(f,d){for(var c;null!=(c=f.next());){if("\x3c"==
+c)return d.tokenize=H(a+1),d.tokenize(f,d);if("\x3e"==c)if(1==a){d.tokenize=B;break}else return d.tokenize=H(a-1),d.tokenize(f,d)}return"meta"}}function w(a,f,d){this.prev=a.context;this.tagName=f;this.indent=a.indented;this.startOfLine=d;if(F.doNotIndent.hasOwnProperty(f)||a.context&&a.context.noIndent)this.noIndent=!0}function h(a){a.context&&(a.context=a.context.prev)}function a(a,f){for(var d;a.context;){d=a.context.tagName;if(!F.contextGrabbers.hasOwnProperty(d)||!F.contextGrabbers[d].hasOwnProperty(f))break;
+h(a)}}function c(a,f,d){return"openTag"==a?(d.tagStart=f.column(),K):"closeTag"==a?x:c}function K(a,f,d){if("word"==a)return d.tagName=f.current(),E="tag",l;E="error";return K}function x(a,f,d){if("word"==a){a=f.current();d.context&&d.context.tagName!=a&&F.implicitlyClosed.hasOwnProperty(d.context.tagName)&&h(d);if(d.context&&d.context.tagName==a||!1===F.matchClosing)return E="tag",t;E="tag error";return m}E="error";return m}function t(a,f,d){if("endTag"!=a)return E="error",t;h(d);return c}function m(a,
+f,d){E="error";return t(a,f,d)}function l(R,f,d){if("word"==R)return E="attribute",D;if("endTag"==R||"selfcloseTag"==R){f=d.tagName;var g=d.tagStart;d.tagName=d.tagStart=null;"selfcloseTag"==R||F.autoSelfClosers.hasOwnProperty(f)?a(d,f):(a(d,f),d.context=new w(d,f,g==d.indented));return c}E="error";return l}function D(a,f,d){if("equals"==a)return u;F.allowMissing||(E="error");return l(a,f,d)}function u(a,f,d){if("string"==a)return L;if("word"==a&&F.allowUnquoted)return E="string",l;E="error";return l(a,
+f,d)}function L(a,f,d){return"string"==a?L:l(a,f,d)}var V=r.indentUnit,F={},Y=n.htmlMode?z:C,S;for(S in Y)F[S]=Y[S];for(S in n)F[S]=n[S];var M,E;B.isInText=!0;return{startState:function(a){var f={tokenize:B,state:c,indented:a||0,tagName:null,tagStart:null,context:null};null!=a&&(f.baseIndent=a);return f},token:function(a,f){!f.tagName&&a.sol()&&(f.indented=a.indentation());if(a.eatSpace())return null;M=null;var d=f.tokenize(a,f);(d||M)&&"comment"!=d&&(E=null,f.state=f.state(M||d,a,f),E&&(d="error"==
+E?d+" error":E));return d},indent:function(a,f,d){var c=a.context;if(a.tokenize.isInAttribute)return a.tagStart==a.indented?a.stringStartCol+1:a.indented+V;if(c&&c.noIndent)return g.Pass;if(a.tokenize!=G&&a.tokenize!=B)return d?d.match(/^(\s*)/)[0].length:0;if(a.tagName)return!1!==F.multilineTagIndentPastTag?a.tagStart+a.tagName.length+2:a.tagStart+V*(F.multilineTagIndentFactor||1);if(F.alignCDATA&&/<!\[CDATA\[/.test(f))return 0;if((f=f&&/^<(\/)?([\w_:\.-]*)/.exec(f))&&f[1])for(;c;)if(c.tagName==
+f[2]){c=c.prev;break}else if(F.implicitlyClosed.hasOwnProperty(c.tagName))c=c.prev;else break;else if(f)for(;c;)if((d=F.contextGrabbers[c.tagName])&&d.hasOwnProperty(f[2]))c=c.prev;else break;for(;c&&c.prev&&!c.startOfLine;)c=c.prev;return c?c.indent+V:a.baseIndent||0},electricInput:/<\/[\s\w:]+>$/,blockCommentStart:"\x3c!--",blockCommentEnd:"--\x3e",configuration:F.htmlMode?"html":"xml",helperType:F.htmlMode?"html":"xml",skipAttribute:function(a){a.state==u&&(a.state=l)}}});g.defineMIME("text/xml",
+"xml");g.defineMIME("application/xml","xml");g.mimeModes.hasOwnProperty("text/html")||g.defineMIME("text/html",{name:"xml",htmlMode:!0})});
+(function(g){"object"==typeof exports&&"object"==typeof module?g(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],g):g(CodeMirror)})(function(g){function z(g,r,n){return/^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(r.lastType)||"quasi"==r.lastType&&/\{\s*$/.test(g.string.slice(0,g.pos-(n||0)))}g.defineMode("javascript",function(C,r){function n(p,a,e){da=p;fa=e;return a}function B(a,e){var b=a.next();if('"'==b||"'"==
+b)return e.tokenize=G(b),e.tokenize(a,e);if("."==b&&a.match(/^\d+(?:[eE][+\-]?\d+)?/))return n("number","number");if("."==b&&a.match(".."))return n("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(b))return n(b);if("\x3d"==b&&a.eat("\x3e"))return n("\x3d\x3e","operator");if("0"==b&&a.eat(/x/i))return a.eatWhile(/[\da-f]/i),n("number","number");if("0"==b&&a.eat(/o/i))return a.eatWhile(/[0-7]/i),n("number","number");if("0"==b&&a.eat(/b/i))return a.eatWhile(/[01]/i),n("number","number");if(/\d/.test(b))return a.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),
+n("number","number");if("/"==b){if(a.eat("*"))return e.tokenize=J,J(a,e);if(a.eat("/"))return a.skipToEnd(),n("comment","comment");if(z(a,e,1)){a:for(var b=!1,v,c=!1;null!=(v=a.next());){if(!b){if("/"==v&&!c)break a;"["==v?c=!0:c&&"]"==v&&(c=!1)}b=!b&&"\\"==v}a.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);return n("regexp","string-2")}a.eatWhile(ga);return n("operator","operator",a.current())}if("`"==b)return e.tokenize=A,A(a,e);if("#"==b)return a.skipToEnd(),n("error","error");if(ga.test(b))return"\x3e"==
+b&&e.lexical&&"\x3e"==e.lexical.type||a.eatWhile(ga),n("operator","operator",a.current());if(ma.test(b)){a.eatWhile(ma);b=a.current();if("."!=e.lastType){if(sa.propertyIsEnumerable(b))return v=sa[b],n(v.type,v.style,b);if("async"==b&&a.match(/^\s*[\(\w]/,!1))return n("async","keyword",b)}return n("variable","variable",b)}}function G(a){return function(e,b){var v=!1,c;if(ha&&"@"==e.peek()&&e.match(Aa))return b.tokenize=B,n("jsonld-keyword","meta");for(;null!=(c=e.next())&&(c!=a||v);)v=!v&&"\\"==c;
+v||(b.tokenize=B);return n("string","string")}}function J(a,e){for(var b=!1,v;v=a.next();){if("/"==v&&b){e.tokenize=B;break}b="*"==v}return n("comment","comment")}function A(a,e){for(var b=!1,v;null!=(v=a.next());){if(!b&&("`"==v||"$"==v&&a.eat("{"))){e.tokenize=B;break}b=!b&&"\\"==v}return n("quasi","string-2",a.current())}function H(a,e){e.fatArrowAt&&(e.fatArrowAt=null);var b=a.string.indexOf("\x3d\x3e",a.start);if(!(0>b)){if(O){var v=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(a.string.slice(a.start,
+b));v&&(b=v.index)}for(var v=0,c=!1,b=b-1;0<=b;--b){var d=a.string.charAt(b),q="([{}])".indexOf(d);if(0<=q&&3>q){if(!v){++b;break}if(0==--v){"("==d&&(c=!0);break}}else if(3<=q&&6>q)++v;else if(ma.test(d))c=!0;else{if(/["'\/]/.test(d))return;if(c&&!v){++b;break}}}c&&!v&&(e.fatArrowAt=b)}}function w(a,e,b,c,d,q){this.indented=a;this.column=e;this.type=b;this.prev=d;this.info=q;null!=c&&(this.align=c)}function h(){for(var a=arguments.length-1;0<=a;a--)k.cc.push(arguments[a])}function a(){h.apply(null,
+arguments);return!0}function c(a){function e(b){for(;b;b=b.next)if(b.name==a)return!0;return!1}var b=k.state;k.marked="def";b.context?e(b.localVars)||(b.localVars={name:a,next:b.localVars}):!e(b.globalVars)&&r.globalVars&&(b.globalVars={name:a,next:b.globalVars})}function K(){k.state.context={prev:k.state.context,vars:k.state.localVars};k.state.localVars=Ba}function x(){k.state.localVars=k.state.context.vars;k.state.context=k.state.context.prev}function t(a,e){var b=function(){var b=k.state,c=b.indented;
+if("stat"==b.lexical.type)c=b.lexical.indented;else for(var d=b.lexical;d&&")"==d.type&&d.align;d=d.prev)c=d.indented;b.lexical=new w(c,k.stream.column(),a,null,b.lexical,e)};b.lex=!0;return b}function m(){var a=k.state;a.lexical.prev&&(")"==a.lexical.type&&(a.indented=a.lexical.indented),a.lexical=a.lexical.prev)}function l(p){function b(e){return e==p?a():";"==p?h():a(b)}return b}function D(p,b){return"var"==p?a(t("vardef",b.length),N,l(";"),m):"keyword a"==p?a(t("form"),V,D,m):"keyword b"==p?a(t("form"),
+D,m):"{"==p?a(t("}"),ia,m):";"==p?a():"if"==p?("else"==k.state.lexical.info&&k.state.cc[k.state.cc.length-1]==m&&k.state.cc.pop()(),a(t("form"),V,D,m,ta)):"function"==p?a(P):"for"==p?a(t("form"),Ca,D,m):"variable"==p?O&&"type"==b?(k.marked="keyword",a(I,l("operator"),I,l(";"))):a(t("stat"),Da):"switch"==p?a(t("form"),V,l("{"),t("}","switch"),ia,m,m):"case"==p?a(u,l(":")):"default"==p?a(l(":")):"catch"==p?a(t("form"),K,l("("),na,l(")"),D,m,x):"class"==p?a(t("form"),ua,m):"export"==p?a(t("stat"),Ea,
+m):"import"==p?a(t("stat"),Fa,m):"module"==p?a(t("form"),e,l("{"),t("}"),ia,m,m):"async"==p?a(D):"@"==b?a(u,D):h(t("stat"),u,l(";"),m)}function u(a){return F(a,!1)}function L(a){return F(a,!0)}function V(p){return"("!=p?h():a(t(")"),u,l(")"),m)}function F(p,b){if(k.state.fatArrowAt==k.stream.start){var c=b?ra:d;if("("==p)return a(K,t(")"),Q(e,")"),m,l("\x3d\x3e"),c,x);if("variable"==p)return h(K,e,l("\x3d\x3e"),c,x)}c=b?E:M;return Ga.hasOwnProperty(p)?a(c):"function"==p?a(P,c):"class"==p?a(t("form"),
+Ha,m):"keyword c"==p||"async"==p?a(b?S:Y):"("==p?a(t(")"),Y,l(")"),m,c):"operator"==p||"spread"==p?a(b?L:u):"["==p?a(t("]"),Ia,m,c):"{"==p?ea(oa,"}",null,c):"quasi"==p?h(R,c):"new"==p?a(za(b)):a()}function Y(a){return a.match(/[;\}\)\],]/)?h():h(u)}function S(a){return a.match(/[;\}\)\],]/)?h():h(L)}function M(p,b){return","==p?a(u):E(p,b,!1)}function E(b,e,c){var v=0==c?M:E,q=0==c?u:L;if("\x3d\x3e"==b)return a(K,c?ra:d,x);if("operator"==b)return/\+\+|--/.test(e)?a(v):"?"==e?a(u,l(":"),q):a(q);if("quasi"==
+b)return h(R,v);if(";"!=b){if("("==b)return ea(L,")","call",v);if("."==b)return a(Ja,v);if("["==b)return a(t("]"),Y,l("]"),m,v);if(O&&"as"==e)return k.marked="keyword",a(I,v)}}function R(b,e){return"quasi"!=b?h():"${"!=e.slice(e.length-2)?a(R):a(u,f)}function f(b){if("}"==b)return k.marked="string-2",k.state.tokenize=A,a(R)}function d(a){H(k.stream,k.state);return h("{"==a?D:u)}function ra(a){H(k.stream,k.state);return h("{"==a?D:L)}function za(b){return function(e){return"."==e?a(b?Ka:La):h(b?L:
+u)}}function La(b,e){if("target"==e)return k.marked="keyword",a(M)}function Ka(b,e){if("target"==e)return k.marked="keyword",a(E)}function Da(b){return":"==b?a(m,D):h(M,l(";"),m)}function Ja(b){if("variable"==b)return k.marked="property",a()}function oa(b,e){if("async"==b)return k.marked="property",a(oa);if("variable"==b||"keyword"==k.style)return k.marked="property","get"==e||"set"==e?a(Ma):a(W);if("number"==b||"string"==b)return k.marked=ha?"property":k.style+" property",a(W);if("jsonld-keyword"==
+b)return a(W);if("modifier"==b)return a(oa);if("["==b)return a(u,l("]"),W);if("spread"==b)return a(u,W);if(":"==b)return h(W)}function Ma(b){if("variable"!=b)return h(W);k.marked="property";return a(P)}function W(b){if(":"==b)return a(L);if("("==b)return h(P)}function Q(b,e,c){function d(q,f){if(c?-1<c.indexOf(q):","==q){var g=k.state.lexical;"call"==g.info&&(g.pos=(g.pos||0)+1);return a(function(a,c){return a==e||c==e?h():h(b)},d)}return q==e||f==e?a():a(l(e))}return function(c,q){return c==e||q==
+e?a():h(b,d)}}function ea(b,e,c){for(var d=3;d<arguments.length;d++)k.cc.push(arguments[d]);return a(t(e,c),Q(b,e),m)}function ia(b){return"}"==b?a():h(D,ia)}function T(b,e){if(O){if(":"==b)return a(I);if("?"==e)return a(T)}}function I(b){if("variable"==b)return k.marked="type",a(y);if("string"==b||"number"==b||"atom"==b)return a(y);if("{"==b)return a(t("}"),Q(Z,"}",",;"),m,y);if("("==b)return a(Q(aa,")"),U)}function U(b){if("\x3d\x3e"==b)return a(I)}function Z(b,e){if("variable"==b||"keyword"==k.style)return k.marked=
+"property",a(Z);if("?"==e)return a(Z);if(":"==b)return a(I);if("["==b)return a(u,T,l("]"),Z)}function aa(b){if("variable"==b)return a(aa);if(":"==b)return a(I)}function y(b,e){if("\x3c"==e)return a(t("\x3e"),Q(I,"\x3e"),m,y);if("|"==e||"."==b)return a(I);if("["==b)return a(l("]"),y);if("extends"==e)return a(I)}function N(){return h(e,T,b,Na)}function e(b,d){if("modifier"==b)return a(e);if("variable"==b)return c(d),a();if("spread"==b)return a(e);if("["==b)return ea(e,"]");if("{"==b)return ea(q,"}")}
+function q(p,d){if("variable"==p&&!k.stream.match(/^\s*:/,!1))return c(d),a(b);"variable"==p&&(k.marked="property");return"spread"==p?a(e):"}"==p?h():a(l(":"),e,b)}function b(b,e){if("\x3d"==e)return a(L)}function Na(b){if(","==b)return a(N)}function ta(b,e){if("keyword b"==b&&"else"==e)return a(t("form","else"),D,m)}function Ca(b){if("("==b)return a(t(")"),Oa,l(")"),m)}function Oa(b){return"var"==b?a(N,l(";"),ja):";"==b?a(ja):"variable"==b?a(Pa):h(u,l(";"),ja)}function Pa(b,e){return"in"==e||"of"==
+e?(k.marked="keyword",a(u)):a(M,ja)}function ja(b,e){return";"==b?a(va):"in"==e||"of"==e?(k.marked="keyword",a(u)):h(u,l(";"),va)}function va(b){")"!=b&&a(u)}function P(b,e){if("*"==e)return k.marked="keyword",a(P);if("variable"==b)return c(e),a(P);if("("==b)return a(K,t(")"),Q(na,")"),m,T,D,x);if(O&&"\x3c"==e)return a(t("\x3e"),Q(I,"\x3e"),m,P)}function na(c){return"spread"==c?a(na):h(e,T,b)}function Ha(a,b){return"variable"==a?ua(a,b):ka(a,b)}function ua(b,e){if("variable"==b)return c(e),a(ka)}
+function ka(b,e){if("\x3c"==e)return a(t("\x3e"),Q(I,"\x3e"),m,ka);if("extends"==e||"implements"==e||O&&","==b)return a(O?I:u,ka);if("{"==b)return a(t("}"),X,m)}function X(b,e){if("variable"==b||"keyword"==k.style){if(("async"==e||"static"==e||"get"==e||"set"==e||O&&("public"==e||"private"==e||"protected"==e||"readonly"==e||"abstract"==e))&&k.stream.match(/^\s+[\w$\xa1-\uffff]/,!1))return k.marked="keyword",a(X);k.marked="property";return a(O?pa:P,X)}if("["==b)return a(u,l("]"),O?pa:P,X);if("*"==
+e)return k.marked="keyword",a(X);if(";"==b)return a(X);if("}"==b)return a();if("@"==e)return a(u,X)}function pa(e,c){return"?"==c?a(pa):":"==e?a(I,b):"\x3d"==c?a(L):h(P)}function Ea(b,e){return"*"==e?(k.marked="keyword",a(qa,l(";"))):"default"==e?(k.marked="keyword",a(u,l(";"))):"{"==b?a(Q(wa,"}"),qa,l(";")):h(D)}function wa(b,e){if("as"==e)return k.marked="keyword",a(l("variable"));if("variable"==b)return h(L,wa)}function Fa(b){return"string"==b?a():h(la,xa,qa)}function la(b,e){if("{"==b)return ea(la,
+"}");"variable"==b&&c(e);"*"==e&&(k.marked="keyword");return a(Qa)}function xa(b){if(","==b)return a(la,xa)}function Qa(b,e){if("as"==e)return k.marked="keyword",a(la)}function qa(b,e){if("from"==e)return k.marked="keyword",a(u)}function Ia(b){return"]"==b?a():h(Q(L,"]"))}var ba=C.indentUnit,ya=r.statementIndent,ha=r.jsonld,ca=r.json||ha,O=r.typescript,ma=r.wordCharacters||/[\w$\xa1-\uffff]/,sa=function(){function a(b){return{type:b,style:"keyword"}}var b=a("keyword a"),e=a("keyword b"),c=a("keyword c"),
+d=a("operator"),q={type:"atom",style:"atom"},b={"if":a("if"),"while":b,"with":b,"else":e,"do":e,"try":e,"finally":e,"return":c,"break":c,"continue":c,"new":a("new"),"delete":c,"throw":c,"debugger":c,"var":a("var"),"const":a("var"),let:a("var"),"function":a("function"),"catch":a("catch"),"for":a("for"),"switch":a("switch"),"case":a("case"),"default":a("default"),"in":d,"typeof":d,"instanceof":d,"true":q,"false":q,"null":q,undefined:q,NaN:q,Infinity:q,"this":a("this"),"class":a("class"),"super":a("atom"),
+yield:c,"export":a("export"),"import":a("import"),"extends":c,await:c};if(O){var e={type:"variable",style:"type"},c={"interface":a("class"),"implements":c,namespace:c,module:a("module"),"enum":a("module"),"public":a("modifier"),"private":a("modifier"),"protected":a("modifier"),"abstract":a("modifier"),string:e,number:e,"boolean":e,any:e},f;for(f in c)b[f]=c[f]}return b}(),ga=/[+\-*&%=<>!?|~^@]/,Aa=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/,da,fa,Ga={atom:!0,
+number:!0,variable:!0,string:!0,regexp:!0,"this":!0,"jsonld-keyword":!0},k={state:null,column:null,marked:null,cc:null},Ba={name:"this",next:{name:"arguments"}};m.lex=!0;return{startState:function(a){a={tokenize:B,lastType:"sof",cc:[],lexical:new w((a||0)-ba,0,"block",!1),localVars:r.localVars,context:r.localVars&&{vars:r.localVars},indented:a||0};r.globalVars&&"object"==typeof r.globalVars&&(a.globalVars=r.globalVars);return a},token:function(a,b){a.sol()&&(b.lexical.hasOwnProperty("align")||(b.lexical.align=
+!1),b.indented=a.indentation(),H(a,b));if(b.tokenize!=J&&a.eatSpace())return null;var e=b.tokenize(a,b);if("comment"==da)return e;b.lastType="operator"!=da||"++"!=fa&&"--"!=fa?da:"incdec";a:{var c=da,d=fa,q=b.cc;k.state=b;k.stream=a;k.marked=null;k.cc=q;k.style=e;b.lexical.hasOwnProperty("align")||(b.lexical.align=!0);for(;;)if((q.length?q.pop():ca?u:D)(c,d)){for(;q.length&&q[q.length-1].lex;)q.pop()();if(k.marked){e=k.marked;break a}if(c="variable"==c)b:{for(c=b.localVars;c;c=c.next)if(c.name==d){c=
+!0;break b}for(q=b.context;q;q=q.prev)for(c=q.vars;c;c=c.next)if(c.name==d){c=!0;break b}c=void 0}if(c){e="variable-2";break a}break a}}return e},indent:function(a,b){if(a.tokenize==J)return g.Pass;if(a.tokenize!=B)return 0;var e=b&&b.charAt(0),c=a.lexical,q;if(!/^\s*else\b/.test(b))for(var d=a.cc.length-1;0<=d;--d){var f=a.cc[d];if(f==m)c=c.prev;else if(f!=ta)break}for(;!("stat"!=c.type&&"form"!=c.type||"}"!=e&&(!(q=a.cc[a.cc.length-1])||q!=M&&q!=E||/^[,\.=+\-*:?[\(]/.test(b)));)c=c.prev;ya&&")"==
+c.type&&"stat"==c.prev.type&&(c=c.prev);q=c.type;d=e==q;return"vardef"==q?c.indented+("operator"==a.lastType||","==a.lastType?c.info+1:0):"form"==q&&"{"==e?c.indented:"form"==q?c.indented+ba:"stat"==q?(e=c.indented,c="operator"==a.lastType||","==a.lastType||ga.test(b.charAt(0))||/[,.]/.test(b.charAt(0)),e+(c?ya||ba:0)):"switch"!=c.info||d||0==r.doubleIndentSwitch?c.align?c.column+(d?0:1):c.indented+(d?0:ba):c.indented+(/^(?:case|default)\b/.test(b)?ba:2*ba)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,
+blockCommentStart:ca?null:"/*",blockCommentEnd:ca?null:"*/",lineComment:ca?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:ca?"json":"javascript",jsonldMode:ha,jsonMode:ca,expressionAllowed:z,skipExpression:function(a){var b=a.cc[a.cc.length-1];b!=u&&b!=L||a.cc.pop()}}});g.registerHelper("wordChars","javascript",/[\w$]/);g.defineMIME("text/javascript","javascript");g.defineMIME("text/ecmascript","javascript");g.defineMIME("application/javascript","javascript");g.defineMIME("application/x-javascript",
+"javascript");g.defineMIME("application/ecmascript","javascript");g.defineMIME("application/json",{name:"javascript",json:!0});g.defineMIME("application/x-json",{name:"javascript",json:!0});g.defineMIME("application/ld+json",{name:"javascript",jsonld:!0});g.defineMIME("text/typescript",{name:"javascript",typescript:!0});g.defineMIME("application/typescript",{name:"javascript",typescript:!0})});
+(function(g){"object"==typeof exports&&"object"==typeof module?g(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],g):g(CodeMirror)})(function(g){function z(a){for(var c={},g=0;g<a.length;++g)c[a[g].toLowerCase()]=!0;return c}function C(a,c){for(var g=!1,h;null!=(h=a.next());){if(g&&"/"==h){c.tokenize=null;break}g="*"==h}return["comment","comment"]}g.defineMode("css",function(a,c){function h(a,c){aa=c;return a}function K(a,c){var b=a.next();if(w[b]){var d=
+w[b](a,c);if(!1!==d)return d}if("@"==b)return a.eatWhile(/[\w\\\-]/),h("def",a.current());if("\x3d"==b||("~"==b||"|"==b)&&a.eat("\x3d"))return h(null,"compare");if('"'==b||"'"==b)return c.tokenize=l(b),c.tokenize(a,c);if("#"==b)return a.eatWhile(/[\w\\\-]/),h("atom","hash");if("!"==b)return a.match(/^\s*\w*/),h("keyword","important");if(/\d/.test(b)||"."==b&&a.eat(/\d/))return a.eatWhile(/[\w.%]/),h("number","unit");if("-"===b){if(/[\d.]/.test(a.peek()))return a.eatWhile(/[\w.%]/),h("number","unit");
+if(a.match(/^-[\w\\\-]+/))return a.eatWhile(/[\w\\\-]/),a.match(/^\s*:/,!1)?h("variable-2","variable-definition"):h("variable-2","variable");if(a.match(/^\w+-/))return h("meta","meta")}else return/[,+>*\/]/.test(b)?h(null,"select-op"):"."==b&&a.match(/^-?[_a-z][_a-z0-9-]*/i)?h("qualifier","qualifier"):/[:;{}\[\]\(\)]/.test(b)?h(null,b):"u"==b&&a.match(/rl(-prefix)?\(/)||"d"==b&&a.match("omain(")||"r"==b&&a.match("egexp(")?(a.backUp(1),c.tokenize=m,h("property","word")):/[\w\\\-]/.test(b)?(a.eatWhile(/[\w\\\-]/),
+h("property","word")):h(null,null)}function l(a){return function(c,b){for(var d=!1,f;null!=(f=c.next());){if(f==a&&!d){")"==a&&c.backUp(1);break}d=!d&&"\\"==f}if(f==a||!d&&")"!=a)b.tokenize=null;return h("string","string")}}function m(a,c){a.next();a.match(/\s*[\"\')]/,!1)?c.tokenize=null:c.tokenize=l(")");return h(null,"(")}function t(a,c,b){this.type=a;this.indent=c;this.prev=b}function x(a,c,b,d){a.context=new t(b,c.indentation()+(!1===d?0:A),a.context);return b}function f(a){a.context.prev&&(a.context=
+a.context.prev);return a.context.type}function d(a,c,b,d){for(d=d||1;0<d;d--)b.context=b.context.prev;return N[b.context.type](a,c,b)}function u(a){a=a.current().toLowerCase();y=I.hasOwnProperty(a)?"atom":T.hasOwnProperty(a)?"keyword":"variable"}var n=c.inline;c.propertyKeywords||(c=g.resolveMode("text/css"));var A=a.indentUnit,w=c.tokenHooks,r=c.documentTypes||{},H=c.mediaTypes||{},J=c.mediaFeatures||{},z=c.mediaValueKeywords||{},B=c.propertyKeywords||{},D=c.nonStandardPropertyKeywords||{},C=c.fontProperties||
+{},G=c.counterDescriptors||{},T=c.colorKeywords||{},I=c.valueKeywords||{},U=c.allowNested,Z=!0===c.supportsAtComponent,aa,y,N={top:function(a,c,b){if("{"==a)return x(b,c,"block");if("}"==a&&b.context.prev)return f(b);if(Z&&/@component/.test(a))return x(b,c,"atComponentBlock");if(/^@(-moz-)?document$/.test(a))return x(b,c,"documentTypes");if(/^@(media|supports|(-moz-)?document|import)$/.test(a))return x(b,c,"atBlock");if(/^@(font-face|counter-style)/.test(a))return b.stateArg=a,"restricted_atBlock_before";
+if(/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(a))return"keyframes";if(a&&"@"==a.charAt(0))return x(b,c,"at");if("hash"==a)y="builtin";else if("word"==a)y="tag";else{if("variable-definition"==a)return"maybeprop";if("interpolation"==a)return x(b,c,"interpolation");if(":"==a)return"pseudo";if(U&&"("==a)return x(b,c,"parens")}return b.context.type},block:function(a,c,b){if("word"==a){a=c.current().toLowerCase();if(B.hasOwnProperty(a))return y="property","maybeprop";if(D.hasOwnProperty(a))return y="string-2",
+"maybeprop";if(U)return y=c.match(/^\s*:(?:\s|$)/,!1)?"property":"tag","block";y+=" error";return"maybeprop"}if("meta"==a)return"block";if(U||"hash"!=a&&"qualifier"!=a)return N.top(a,c,b);y="error";return"block"},maybeprop:function(a,c,b){return":"==a?x(b,c,"prop"):N[b.context.type](a,c,b)},prop:function(a,c,b){if(";"==a)return f(b);if("{"==a&&U)return x(b,c,"propBlock");if("}"==a||"{"==a)return d(a,c,b);if("("==a)return x(b,c,"parens");if("hash"==a&&!/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(c.current()))y+=
+" error";else if("word"==a)u(c);else if("interpolation"==a)return x(b,c,"interpolation");return"prop"},propBlock:function(a,c,b){return"}"==a?f(b):"word"==a?(y="property","maybeprop"):b.context.type},parens:function(a,c,b){if("{"==a||"}"==a)return d(a,c,b);if(")"==a)return f(b);if("("==a)return x(b,c,"parens");if("interpolation"==a)return x(b,c,"interpolation");"word"==a&&u(c);return"parens"},pseudo:function(a,c,b){return"meta"==a?"pseudo":"word"==a?(y="variable-3",b.context.type):N[b.context.type](a,
+c,b)},documentTypes:function(a,c,b){return"word"==a&&r.hasOwnProperty(c.current())?(y="tag",b.context.type):N.atBlock(a,c,b)},atBlock:function(a,c,b){if("("==a)return x(b,c,"atBlock_parens");if("}"==a||";"==a)return d(a,c,b);if("{"==a)return f(b)&&x(b,c,U?"block":"top");if("interpolation"==a)return x(b,c,"interpolation");"word"==a&&(a=c.current().toLowerCase(),y="only"==a||"not"==a||"and"==a||"or"==a?"keyword":H.hasOwnProperty(a)?"attribute":J.hasOwnProperty(a)?"property":z.hasOwnProperty(a)?"keyword":
+B.hasOwnProperty(a)?"property":D.hasOwnProperty(a)?"string-2":I.hasOwnProperty(a)?"atom":T.hasOwnProperty(a)?"keyword":"error");return b.context.type},atComponentBlock:function(a,c,b){if("}"==a)return d(a,c,b);if("{"==a)return f(b)&&x(b,c,U?"block":"top",!1);"word"==a&&(y="error");return b.context.type},atBlock_parens:function(a,c,b){return")"==a?f(b):"{"==a||"}"==a?d(a,c,b,2):N.atBlock(a,c,b)},restricted_atBlock_before:function(a,c,b){return"{"==a?x(b,c,"restricted_atBlock"):"word"==a&&"@counter-style"==
+b.stateArg?(y="variable","restricted_atBlock_before"):N[b.context.type](a,c,b)},restricted_atBlock:function(a,c,b){return"}"==a?(b.stateArg=null,f(b)):"word"==a?(y="@font-face"==b.stateArg&&!C.hasOwnProperty(c.current().toLowerCase())||"@counter-style"==b.stateArg&&!G.hasOwnProperty(c.current().toLowerCase())?"error":"property","maybeprop"):"restricted_atBlock"},keyframes:function(a,c,b){return"word"==a?(y="variable","keyframes"):"{"==a?x(b,c,"top"):N[b.context.type](a,c,b)},at:function(a,c,b){if(";"==
+a)return f(b);if("{"==a||"}"==a)return d(a,c,b);"word"==a?y="tag":"hash"==a&&(y="builtin");return"at"},interpolation:function(a,c,b){if("}"==a)return f(b);if("{"==a||";"==a)return d(a,c,b);"word"==a?y="variable":"variable"!=a&&"("!=a&&")"!=a&&(y="error");return"interpolation"}};return{startState:function(a){return{tokenize:null,state:n?"block":"top",stateArg:null,context:new t(n?"block":"top",a||0,null)}},token:function(a,c){if(!c.tokenize&&a.eatSpace())return null;var b=(c.tokenize||K)(a,c);b&&"object"==
+typeof b&&(aa=b[1],b=b[0]);y=b;c.state=N[c.state](aa,a,c);return y},indent:function(a,c){var b=a.context,d=c&&c.charAt(0),f=b.indent;"prop"!=b.type||"}"!=d&&")"!=d||(b=b.prev);if(b.prev)if("}"==d&&("block"==b.type||"top"==b.type||"interpolation"==b.type||"restricted_atBlock"==b.type))b=b.prev,f=b.indent;else if(")"==d&&("parens"==b.type||"atBlock_parens"==b.type)||"{"==d&&("at"==b.type||"atBlock"==b.type))f=Math.max(0,b.indent-A);return f},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",
+lineComment:c.lineComment,fold:"brace"}});var r=["domain","regexp","url","url-prefix"],n=z(r),B="all aural braille handheld print projection screen tty tv embossed".split(" "),G=z(B),J="width min-width max-width height min-height max-height device-width min-device-width max-device-width device-height min-device-height max-device-height aspect-ratio min-aspect-ratio max-aspect-ratio device-aspect-ratio min-device-aspect-ratio max-device-aspect-ratio color min-color max-color color-index min-color-index max-color-index monochrome min-monochrome max-monochrome resolution min-resolution max-resolution scan grid orientation device-pixel-ratio min-device-pixel-ratio max-device-pixel-ratio pointer any-pointer hover any-hover".split(" "),
+A=z(J),H="landscape portrait none coarse fine on-demand hover interlace progressive".split(" "),w=z(H),h="align-content align-items align-self alignment-adjust alignment-baseline anchor-point animation animation-delay animation-direction animation-duration animation-fill-mode animation-iteration-count animation-name animation-play-state animation-timing-function appearance azimuth backface-visibility background background-attachment background-blend-mode background-clip background-color background-image background-origin background-position background-repeat background-size baseline-shift binding bleed bookmark-label bookmark-level bookmark-state bookmark-target border border-bottom border-bottom-color border-bottom-left-radius border-bottom-right-radius border-bottom-style border-bottom-width border-collapse border-color border-image border-image-outset border-image-repeat border-image-slice border-image-source border-image-width border-left border-left-color border-left-style border-left-width border-radius border-right border-right-color border-right-style border-right-width border-spacing border-style border-top border-top-color border-top-left-radius border-top-right-radius border-top-style border-top-width border-width bottom box-decoration-break box-shadow box-sizing break-after break-before break-inside caption-side caret-color clear clip color color-profile column-count column-fill column-gap column-rule column-rule-color column-rule-style column-rule-width column-span column-width columns content counter-increment counter-reset crop cue cue-after cue-before cursor direction display dominant-baseline drop-initial-after-adjust drop-initial-after-align drop-initial-before-adjust drop-initial-before-align drop-initial-size drop-initial-value elevation empty-cells fit fit-position flex flex-basis flex-direction flex-flow flex-grow flex-shrink flex-wrap float float-offset flow-from flow-into font font-feature-settings font-family font-kerning font-language-override font-size font-size-adjust font-stretch font-style font-synthesis font-variant font-variant-alternates font-variant-caps font-variant-east-asian font-variant-ligatures font-variant-numeric font-variant-position font-weight grid grid-area grid-auto-columns grid-auto-flow grid-auto-rows grid-column grid-column-end grid-column-gap grid-column-start grid-gap grid-row grid-row-end grid-row-gap grid-row-start grid-template grid-template-areas grid-template-columns grid-template-rows hanging-punctuation height hyphens icon image-orientation image-rendering image-resolution inline-box-align justify-content justify-items justify-self left letter-spacing line-break line-height line-stacking line-stacking-ruby line-stacking-shift line-stacking-strategy list-style list-style-image list-style-position list-style-type margin margin-bottom margin-left margin-right margin-top marks marquee-direction marquee-loop marquee-play-count marquee-speed marquee-style max-height max-width min-height min-width move-to nav-down nav-index nav-left nav-right nav-up object-fit object-position opacity order orphans outline outline-color outline-offset outline-style outline-width overflow overflow-style overflow-wrap overflow-x overflow-y padding padding-bottom padding-left padding-right padding-top page page-break-after page-break-before page-break-inside page-policy pause pause-after pause-before perspective perspective-origin pitch pitch-range place-content place-items place-self play-during position presentation-level punctuation-trim quotes region-break-after region-break-before region-break-inside region-fragment rendering-intent resize rest rest-after rest-before richness right rotation rotation-point ruby-align ruby-overhang ruby-position ruby-span shape-image-threshold shape-inside shape-margin shape-outside size speak speak-as speak-header speak-numeral speak-punctuation speech-rate stress string-set tab-size table-layout target target-name target-new target-position text-align text-align-last text-decoration text-decoration-color text-decoration-line text-decoration-skip text-decoration-style text-emphasis text-emphasis-color text-emphasis-position text-emphasis-style text-height text-indent text-justify text-outline text-overflow text-shadow text-size-adjust text-space-collapse text-transform text-underline-position text-wrap top transform transform-origin transform-style transition transition-delay transition-duration transition-property transition-timing-function unicode-bidi user-select vertical-align visibility voice-balance voice-duration voice-family voice-pitch voice-range voice-rate voice-stress voice-volume volume white-space widows width will-change word-break word-spacing word-wrap z-index clip-path clip-rule mask enable-background filter flood-color flood-opacity lighting-color stop-color stop-opacity pointer-events color-interpolation color-interpolation-filters color-rendering fill fill-opacity fill-rule image-rendering marker marker-end marker-mid marker-start shape-rendering stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-rendering baseline-shift dominant-baseline glyph-orientation-horizontal glyph-orientation-vertical text-anchor writing-mode".split(" "),
+a=z(h),c="scrollbar-arrow-color scrollbar-base-color scrollbar-dark-shadow-color scrollbar-face-color scrollbar-highlight-color scrollbar-shadow-color scrollbar-3d-light-color scrollbar-track-color shape-inside searchfield-cancel-button searchfield-decoration searchfield-results-button searchfield-results-decoration zoom".split(" "),K=z(c),x=z("font-family src unicode-range font-variant font-feature-settings font-stretch font-weight font-style".split(" ")),t=z("additive-symbols fallback negative pad prefix range speak-as suffix symbols system".split(" ")),
+m="aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkturquoise darkviolet deeppink deepskyblue dimgray dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray grey green greenyellow honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightpink lightsalmon lightseagreen lightskyblue lightslategray lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray snow springgreen steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen".split(" "),
+l=z(m),D="above absolute activeborder additive activecaption afar after-white-space ahead alias all all-scroll alphabetic alternate always amharic amharic-abegede antialiased appworkspace arabic-indic armenian asterisks attr auto auto-flow avoid avoid-column avoid-page avoid-region background backwards baseline below bidi-override binary bengali blink block block-axis bold bolder border border-box both bottom break break-all break-word bullets button button-bevel buttonface buttonhighlight buttonshadow buttontext calc cambodian capitalize caps-lock-indicator caption captiontext caret cell center checkbox circle cjk-decimal cjk-earthly-branch cjk-heavenly-stem cjk-ideographic clear clip close-quote col-resize collapse color color-burn color-dodge column column-reverse compact condensed contain content contents content-box context-menu continuous copy counter counters cover crop cross crosshair currentcolor cursive cyclic darken dashed decimal decimal-leading-zero default default-button dense destination-atop destination-in destination-out destination-over devanagari difference disc discard disclosure-closed disclosure-open document dot-dash dot-dot-dash dotted double down e-resize ease ease-in ease-in-out ease-out element ellipse ellipsis embed end ethiopic ethiopic-abegede ethiopic-abegede-am-et ethiopic-abegede-gez ethiopic-abegede-ti-er ethiopic-abegede-ti-et ethiopic-halehame-aa-er ethiopic-halehame-aa-et ethiopic-halehame-am-et ethiopic-halehame-gez ethiopic-halehame-om-et ethiopic-halehame-sid-et ethiopic-halehame-so-et ethiopic-halehame-ti-er ethiopic-halehame-ti-et ethiopic-halehame-tig ethiopic-numeric ew-resize exclusion expanded extends extra-condensed extra-expanded fantasy fast fill fixed flat flex flex-end flex-start footnotes forwards from geometricPrecision georgian graytext grid groove gujarati gurmukhi hand hangul hangul-consonant hard-light hebrew help hidden hide higher highlight highlighttext hiragana hiragana-iroha horizontal hsl hsla hue icon ignore inactiveborder inactivecaption inactivecaptiontext infinite infobackground infotext inherit initial inline inline-axis inline-block inline-flex inline-grid inline-table inset inside intrinsic invert italic japanese-formal japanese-informal justify kannada katakana katakana-iroha keep-all khmer korean-hangul-formal korean-hanja-formal korean-hanja-informal landscape lao large larger left level lighter lighten line-through linear linear-gradient lines list-item listbox listitem local logical loud lower lower-alpha lower-armenian lower-greek lower-hexadecimal lower-latin lower-norwegian lower-roman lowercase ltr luminosity malayalam match matrix matrix3d media-controls-background media-current-time-display media-fullscreen-button media-mute-button media-play-button media-return-to-realtime-button media-rewind-button media-seek-back-button media-seek-forward-button media-slider media-sliderthumb media-time-remaining-display media-volume-slider media-volume-slider-container media-volume-sliderthumb medium menu menulist menulist-button menulist-text menulist-textfield menutext message-box middle min-intrinsic mix mongolian monospace move multiple multiply myanmar n-resize narrower ne-resize nesw-resize no-close-quote no-drop no-open-quote no-repeat none normal not-allowed nowrap ns-resize numbers numeric nw-resize nwse-resize oblique octal opacity open-quote optimizeLegibility optimizeSpeed oriya oromo outset outside outside-shape overlay overline padding padding-box painted page paused persian perspective plus-darker plus-lighter pointer polygon portrait pre pre-line pre-wrap preserve-3d progress push-button radial-gradient radio read-only read-write read-write-plaintext-only rectangle region relative repeat repeating-linear-gradient repeating-radial-gradient repeat-x repeat-y reset reverse rgb rgba ridge right rotate rotate3d rotateX rotateY rotateZ round row row-resize row-reverse rtl run-in running s-resize sans-serif saturation scale scale3d scaleX scaleY scaleZ screen scroll scrollbar scroll-position se-resize searchfield searchfield-cancel-button searchfield-decoration searchfield-results-button searchfield-results-decoration self-start self-end semi-condensed semi-expanded separate serif show sidama simp-chinese-formal simp-chinese-informal single skew skewX skewY skip-white-space slide slider-horizontal slider-vertical sliderthumb-horizontal sliderthumb-vertical slow small small-caps small-caption smaller soft-light solid somali source-atop source-in source-out source-over space space-around space-between space-evenly spell-out square square-button start static status-bar stretch stroke sub subpixel-antialiased super sw-resize symbolic symbols system-ui table table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group tamil telugu text text-bottom text-top textarea textfield thai thick thin threeddarkshadow threedface threedhighlight threedlightshadow threedshadow tibetan tigre tigrinya-er tigrinya-er-abegede tigrinya-et tigrinya-et-abegede to top trad-chinese-formal trad-chinese-informal transform translate translate3d translateX translateY translateZ transparent ultra-condensed ultra-expanded underline unset up upper-alpha upper-armenian upper-greek upper-hexadecimal upper-latin upper-norwegian upper-roman uppercase urdu url var vertical vertical-text visible visibleFill visiblePainted visibleStroke visual w-resize wait wave wider window windowframe windowtext words wrap wrap-reverse x-large x-small xor xx-large xx-small".split(" "),
+u=z(D),r=r.concat(B).concat(J).concat(H).concat(h).concat(c).concat(m).concat(D);g.registerHelper("hintWords","css",r);g.defineMIME("text/css",{documentTypes:n,mediaTypes:G,mediaFeatures:A,mediaValueKeywords:w,propertyKeywords:a,nonStandardPropertyKeywords:K,fontProperties:x,counterDescriptors:t,colorKeywords:l,valueKeywords:u,tokenHooks:{"/":function(a,c){if(!a.eat("*"))return!1;c.tokenize=C;return C(a,c)}},name:"css"});g.defineMIME("text/x-scss",{mediaTypes:G,mediaFeatures:A,mediaValueKeywords:w,
+propertyKeywords:a,nonStandardPropertyKeywords:K,colorKeywords:l,valueKeywords:u,fontProperties:x,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(a,c){return a.eat("/")?(a.skipToEnd(),["comment","comment"]):a.eat("*")?(c.tokenize=C,C(a,c)):["operator","operator"]},":":function(a){return a.match(/\s*\{/,!1)?[null,null]:!1},$:function(a){a.match(/^[\w-]+/);return a.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"#":function(a){return a.eat("{")?[null,"interpolation"]:
+!1}},name:"css",helperType:"scss"});g.defineMIME("text/x-less",{mediaTypes:G,mediaFeatures:A,mediaValueKeywords:w,propertyKeywords:a,nonStandardPropertyKeywords:K,colorKeywords:l,valueKeywords:u,fontProperties:x,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(a,c){return a.eat("/")?(a.skipToEnd(),["comment","comment"]):a.eat("*")?(c.tokenize=C,C(a,c)):["operator","operator"]},"@":function(a){if(a.eat("{"))return[null,"interpolation"];if(a.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/,
+!1))return!1;a.eatWhile(/[\w\\\-]/);return a.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"\x26":function(){return["atom","atom"]}},name:"css",helperType:"less"});g.defineMIME("text/x-gss",{documentTypes:n,mediaTypes:G,mediaFeatures:A,propertyKeywords:a,nonStandardPropertyKeywords:K,fontProperties:x,counterDescriptors:t,colorKeywords:l,valueKeywords:u,supportsAtComponent:!0,tokenHooks:{"/":function(a,c){if(!a.eat("*"))return!1;c.tokenize=C;return C(a,c)}},name:"css",
+helperType:"gss"})});
+(function(g){"object"==typeof exports&&"object"==typeof module?g(require("../../lib/codemirror"),require("../xml/xml"),require("../javascript/javascript"),require("../css/css")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","../xml/xml","../javascript/javascript","../css/css"],g):g(CodeMirror)})(function(g){function z(g){var n=G[g];return n?n:G[g]=new RegExp("\\s+"+g+"\\s*\x3d\\s*('|\")?([^'\"]+)('|\")?\\s*")}function C(g,n){var r=g.match(z(n));return r?/^\s*(.*?)\s*$/.exec(r[2])[1]:
+""}function r(g,n){for(var r in g)for(var w=n[r]||(n[r]=[]),h=g[r],a=h.length-1;0<=a;a--)w.unshift(h[a])}function n(g,n){for(var r=0;r<g.length;r++){var w=g[r];if(!w[0]||w[1].test(C(n,w[0])))return w[2]}}var B={script:[["lang",/(javascript|babel)/i,"javascript"],["type",/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i,"javascript"],["type",/./,"text/plain"],[null,null,"javascript"]],style:[["lang",/^css$/i,"css"],["type",/^(text\/)?(x-)?(stylesheet|css)$/i,"css"],["type",/./,"text/plain"],
+[null,null,"css"]]},G={};g.defineMode("htmlmixed",function(z,A){function C(a,c){var t=w.token(a,c.htmlState),m=/\btag\b/.test(t),l;if(m&&!/[<>\s\/]/.test(a.current())&&(l=c.htmlState.tagName&&c.htmlState.tagName.toLowerCase())&&h.hasOwnProperty(l))c.inTag=l+" ";else if(c.inTag&&m&&/>$/.test(a.current())){m=/^([\S]+) (.*)/.exec(c.inTag);c.inTag=null;l="\x3e"==a.current()&&n(h[m[1]],m[2]);l=g.getMode(z,l);var r=new RegExp("^\x3c/s*"+m[1]+"s*\x3e","i"),u=new RegExp("\x3c/s*"+m[1]+"s*\x3e","i");c.token=
+function(a,c){if(a.match(r,!1))return c.token=C,c.localState=c.localMode=null;var g=c.localMode.token(a,c.localState),h=a.current(),l=h.search(u);-1<l?a.backUp(h.length-l):h.match(/<\/?$/)&&(a.backUp(h.length),a.match(u,!1)||a.match(h));return g};c.localMode=l;c.localState=g.startState(l,w.indent(c.htmlState,""))}else c.inTag&&(c.inTag+=a.current(),a.eol()&&(c.inTag+=" "));return t}var w=g.getMode(z,{name:"xml",htmlMode:!0,multilineTagIndentFactor:A.multilineTagIndentFactor,multilineTagIndentPastTag:A.multilineTagIndentPastTag}),
+h={},a=A&&A.tags,c=A&&A.scriptTypes;r(B,h);a&&r(a,h);if(c)for(a=c.length-1;0<=a;a--)h.script.unshift(["type",c[a].matches,c[a].mode]);return{startState:function(){var a=g.startState(w);return{token:C,inTag:null,localMode:null,localState:null,htmlState:a}},copyState:function(a){var c;a.localState&&(c=g.copyState(a.localMode,a.localState));return{token:a.token,inTag:a.inTag,localMode:a.localMode,localState:c,htmlState:g.copyState(w,a.htmlState)}},token:function(a,c){return c.token(a,c)},indent:function(a,
+c,h){return!a.localMode||/^\s*<\//.test(c)?w.indent(a.htmlState,c):a.localMode.indent?a.localMode.indent(a.localState,c,h):g.Pass},innerMode:function(a){return{state:a.localState||a.htmlState,mode:a.localMode||w}}}},"xml","javascript","css");g.defineMIME("text/html","htmlmixed")});
+CodeMirror.defineMode("bbcodemixed",function(g){var z,C,r,n,B,G,J;function A(a){return a.replace(/([\[\]\.\-\+\<\>\?\:\(\)\{\}])/g,"\\$1")}var H,w=CodeMirror.getMode(g,"htmlmixed"),h=CodeMirror.getMode(g,"bbcode");J="literal";g.hasOwnProperty("bbCodeLiteral")&&(J=g.bbCodeLiteral);r=/.*\[/;n=/[^\<\>]*\[/;B=new RegExp(A("["+J+"]"));G=new RegExp(A("[/"+J+"]"));H={chain:function(a,c,g){c.tokenize=g;return g(a,c)},cleanChain:function(a,c,g){c.tokenize=null;c.localState=null;c.localMode=null;return"string"==
+typeof g?g?g:null:g(a,c)},maybeBackup:function(a,c,g){c=A(c);var h=a.current(),n=h.search(c);-1<n?a.backUp(h.length-n):h.match(/<\/?$/)&&(a.backUp(h.length),a.match(c,!1)||a.match(h[0]));return g}};z=function(a,c){return!c.inLiteral&&a.match(n,!1)&&null===c.htmlMixedState.htmlState.tagName||!c.inLiteral&&a.match("[",!1)?(c.tokenize=C,c.localMode=h,c.localState=h.startState(w.indent(c.htmlMixedState,"")),H.maybeBackup(a,"[",h.token(a,c.localState))):w.token(a,c.htmlMixedState)};C=function(a,c){return a.match("]",
+!1)?(a.eat("]"),c.tokenize=z,c.localMode=w,c.localState=c.htmlMixedState,"tag"):H.maybeBackup(a,"]",h.token(a,c.localState))};return{startState:function(){var a=w.startState();return{token:z,localMode:null,localState:null,htmlMixedState:a,tokenize:null,inLiteral:!1}},copyState:function(a){var c=null,g=a.tokenize||a.token;a.localState&&(c=CodeMirror.copyState(g!=z?h:w,a.localState));return{token:a.token,tokenize:a.tokenize,localMode:a.localMode,localState:c,htmlMixedState:CodeMirror.copyState(w,a.htmlMixedState),
+inLiteral:a.inLiteral}},token:function(a,c){if(a.match("[",!1)){if(!c.inLiteral&&a.match(B,!0))return c.inLiteral=!0,"keyword";if(c.inLiteral&&a.match(G,!0))return c.inLiteral=!1,"keyword"}c.inLiteral&&c.localState!=c.htmlMixedState&&(c.tokenize=z,c.localMode=w,c.localState=c.htmlMixedState);return(c.tokenize||c.token)(a,c)},indent:function(a,c){return a.localMode==h||a.inLiteral&&!a.localMode||r.test(c)?CodeMirror.Pass:w.indent(a.htmlMixedState,c)},innerMode:function(a){return{state:a.localState||
+a.htmlMixedState,mode:a.localMode||w}}}},"xml","javascript","css");CodeMirror.defineMIME("text/x-bbcode","bbcodemixed");
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/js/codemirror.mode.htmlmixed.min.js b/js/ckeditor/plugins/codemirror/js/codemirror.mode.htmlmixed.min.js
new file mode 100644 (file)
index 0000000..eb0fa7c
--- /dev/null
@@ -0,0 +1,77 @@
+!function(d){"object"==typeof exports&&"object"==typeof module?d(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("mode/xml/xml",["../../lib/codemirror"],d):d(CodeMirror)}(function(d){var p={autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,
+dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0,
+caseFold:!0},B={autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1,caseFold:!1};d.defineMode("xml",function(x,b){function n(a,b){function H(H){return b.tokenize=H,H(a,b)}var d=a.next();if("\x3c"==d)return a.eat("!")?a.eat("[")?a.match("CDATA[")?H(k("atom","]]\x3e")):null:a.match("--")?H(k("comment","--\x3e")):a.match("DOCTYPE",!0,!0)?(a.eatWhile(/[\w\._\-]/),H(y(1))):null:a.eat("?")?(a.eatWhile(/[\w\._\-]/),b.tokenize=k("meta","?\x3e"),"meta"):
+(K=a.eat("/")?"closeTag":"openTag",b.tokenize=q,"tag bracket");if("\x26"==d){var m;return m=a.eat("#")?a.eat("x")?a.eatWhile(/[a-fA-F\d]/)&&a.eat(";"):a.eatWhile(/[\d]/)&&a.eat(";"):a.eatWhile(/[\w\.\-:]/)&&a.eat(";"),m?"atom":"error"}return a.eatWhile(/[^&<]/),null}function q(a,b){var H=a.next();return"\x3e"==H||"/"==H&&a.eat("\x3e")?(b.tokenize=n,K="\x3e"==H?"endTag":"selfcloseTag","tag bracket"):"\x3d"==H?(K="equals",null):"\x3c"==H?(b.tokenize=n,b.state=E,b.tagName=b.tagStart=null,(H=b.tokenize(a,
+b))?H+" tag error":"tag error"):/[\'\"]/.test(H)?(b.tokenize=A(H),b.stringStartCol=a.column(),b.tokenize(a,b)):(a.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/),"word")}function A(a){var b=function(b,d){for(;!b.eol();)if(b.next()==a){d.tokenize=q;break}return"string"};return b.isInAttribute=!0,b}function k(a,b){return function(d,m){for(;!d.eol();){if(d.match(b)){m.tokenize=n;break}d.next()}return a}}function y(a){return function(b,d){for(var m;null!=(m=b.next());){if("\x3c"==m)return d.tokenize=
+y(a+1),d.tokenize(b,d);if("\x3e"==m){if(1==a){d.tokenize=n;break}return d.tokenize=y(a-1),d.tokenize(b,d)}}return"meta"}}function C(a,b,d){this.prev=a.context;this.tagName=b;this.indent=a.indented;this.startOfLine=d;(G.doNotIndent.hasOwnProperty(b)||a.context&&a.context.noIndent)&&(this.noIndent=!0)}function g(a){a.context&&(a.context=a.context.prev)}function a(a,b){for(var d;a.context&&(d=a.context.tagName,G.contextGrabbers.hasOwnProperty(d)&&G.contextGrabbers[d].hasOwnProperty(b));)g(a)}function E(a,
+b,d){return"openTag"==a?(d.tagStart=b.column(),w):"closeTag"==a?J:E}function w(a,b,d){return"word"==a?(d.tagName=b.current(),F="tag",h):(F="error",w)}function J(a,b,d){return"word"==a?(a=b.current(),d.context&&d.context.tagName!=a&&G.implicitlyClosed.hasOwnProperty(d.context.tagName)&&g(d),d.context&&d.context.tagName==a||!1===G.matchClosing?(F="tag",v):(F="tag error",r)):(F="error",r)}function v(a,b,d){return"endTag"!=a?(F="error",v):(g(d),E)}function r(a,b,d){return F="error",v(a,b,d)}function h(b,
+d,m){if("word"==b)return F="attribute",D;if("endTag"==b||"selfcloseTag"==b){d=m.tagName;var q=m.tagStart;return m.tagName=m.tagStart=null,"selfcloseTag"==b||G.autoSelfClosers.hasOwnProperty(d)?a(m,d):(a(m,d),m.context=new C(m,d,q==m.indented)),E}return F="error",h}function D(a,b,d){return"equals"==a?u:(G.allowMissing||(F="error"),h(a,b,d))}function u(a,b,d){return"string"==a?m:"word"==a&&G.allowUnquoted?(F="string",h):(F="error",h(a,b,d))}function m(a,b,d){return"string"==a?m:h(a,b,d)}var R=x.indentUnit,
+G={},W=b.htmlMode?p:B,P;for(P in W)G[P]=W[P];for(P in b)G[P]=b[P];var K,F;return n.isInText=!0,{startState:function(a){var b={tokenize:n,state:E,indented:a||0,tagName:null,tagStart:null,context:null};return null!=a&&(b.baseIndent=a),b},token:function(a,b){if(!b.tagName&&a.sol()&&(b.indented=a.indentation()),a.eatSpace())return null;K=null;var d=b.tokenize(a,b);return(d||K)&&"comment"!=d&&(F=null,b.state=b.state(K||d,a,b),F&&(d="error"==F?d+" error":F)),d},indent:function(a,b,m){var g=a.context;if(a.tokenize.isInAttribute)return a.tagStart==
+a.indented?a.stringStartCol+1:a.indented+R;if(g&&g.noIndent)return d.Pass;if(a.tokenize!=q&&a.tokenize!=n)return m?m.match(/^(\s*)/)[0].length:0;if(a.tagName)return!1!==G.multilineTagIndentPastTag?a.tagStart+a.tagName.length+2:a.tagStart+R*(G.multilineTagIndentFactor||1);if(G.alignCDATA&&/<!\[CDATA\[/.test(b))return 0;if((b=b&&/^<(\/)?([\w_:\.-]*)/.exec(b))&&b[1])for(;g;){if(g.tagName==b[2]){g=g.prev;break}if(!G.implicitlyClosed.hasOwnProperty(g.tagName))break;g=g.prev}else if(b)for(;g;){m=G.contextGrabbers[g.tagName];
+if(!m||!m.hasOwnProperty(b[2]))break;g=g.prev}for(;g&&g.prev&&!g.startOfLine;)g=g.prev;return g?g.indent+R:a.baseIndent||0},electricInput:/<\/[\s\w:]+>$/,blockCommentStart:"\x3c!--",blockCommentEnd:"--\x3e",configuration:G.htmlMode?"html":"xml",helperType:G.htmlMode?"html":"xml",skipAttribute:function(a){a.state==u&&(a.state=h)}}});d.defineMIME("text/xml","xml");d.defineMIME("application/xml","xml");d.mimeModes.hasOwnProperty("text/html")||d.defineMIME("text/html",{name:"xml",htmlMode:!0})});
+(function(d){"object"==typeof exports&&"object"==typeof module?d(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("mode/javascript/javascript",["../../lib/codemirror"],d):d(CodeMirror)})(function(d){function p(d,p,b){return/^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(p.lastType)||"quasi"==p.lastType&&/\{\s*$/.test(d.string.slice(0,d.pos-(b||0)))}d.defineMode("javascript",function(B,x){function b(f,a,c){return aa=f,ca=c,a}function n(f,a){var c=
+f.next();if('"'==c||"'"==c)return a.tokenize=q(c),a.tokenize(f,a);if("."==c&&f.match(/^\d+(?:[eE][+\-]?\d+)?/))return b("number","number");if("."==c&&f.match(".."))return b("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(c))return b(c);if("\x3d"==c&&f.eat("\x3e"))return b("\x3d\x3e","operator");if("0"==c&&f.eat(/x/i))return f.eatWhile(/[\da-f]/i),b("number","number");if("0"==c&&f.eat(/o/i))return f.eatWhile(/[0-7]/i),b("number","number");if("0"==c&&f.eat(/b/i))return f.eatWhile(/[01]/i),b("number",
+"number");if(/\d/.test(c))return f.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),b("number","number");if("/"==c){if(f.eat("*"))c=(a.tokenize=A,A(f,a));else if(f.eat("/"))c=(f.skipToEnd(),b("comment","comment"));else if(p(f,a,1)){a:for(var e=!1,d=!1;null!=(c=f.next());){if(!e){if("/"==c&&!d)break a;"["==c?d=!0:d&&"]"==c&&(d=!1)}e=!e&&"\\"==c}c=(f.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/),b("regexp","string-2"))}else c=(f.eatWhile(da),b("operator","operator",f.current()));return c}if("`"==c)return a.tokenize=
+k,k(f,a);if("#"==c)return f.skipToEnd(),b("error","error");if(da.test(c))return"\x3e"==c&&a.lexical&&"\x3e"==a.lexical.type||f.eatWhile(da),b("operator","operator",f.current());if(ka.test(c)){f.eatWhile(ka);c=f.current();if("."!=a.lastType){if(qa.propertyIsEnumerable(c))return e=qa[c],b(e.type,e.style,c);if("async"==c&&f.match(/^\s*[\(\w]/,!1))return b("async","keyword",c)}return b("variable","variable",c)}}function q(f){return function(a,c){var e,d=!1;if(ea&&"@"==a.peek()&&a.match(Aa))return c.tokenize=
+n,b("jsonld-keyword","meta");for(;null!=(e=a.next())&&(e!=f||d);)d=!d&&"\\"==e;return d||(c.tokenize=n),b("string","string")}}function A(f,a){for(var c,e=!1;c=f.next();){if("/"==c&&e){a.tokenize=n;break}e="*"==c}return b("comment","comment")}function k(f,a){for(var c,e=!1;null!=(c=f.next());){if(!e&&("`"==c||"$"==c&&f.eat("{"))){a.tokenize=n;break}e=!e&&"\\"==c}return b("quasi","string-2",f.current())}function y(f,a){a.fatArrowAt&&(a.fatArrowAt=null);var c=f.string.indexOf("\x3d\x3e",f.start);if(!(0>
+c)){if(L){var e=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(f.string.slice(f.start,c));e&&(c=e.index)}for(var e=0,b=!1,c=c-1;0<=c;--c){var d=f.string.charAt(c),t=Ba.indexOf(d);if(0<=t&&3>t){if(!e){++c;break}if(0==--e){"("==d&&(b=!0);break}}else if(3<=t&&6>t)++e;else if(ka.test(d))b=!0;else{if(/["'\/]/.test(d))return;if(b&&!e){++c;break}}}b&&!e&&(a.fatArrowAt=c)}}function C(f,a,c,e,b,d){this.indented=f;this.column=a;this.type=c;this.prev=b;this.info=d;null!=e&&(this.align=e)}function g(){for(var f=
+arguments.length-1;0<=f;f--)l.cc.push(arguments[f])}function a(){return g.apply(null,arguments),!0}function E(f){function a(c){for(;c;c=c.next)if(c.name==f)return!0;return!1}var c=l.state;(l.marked="def",c.context)?a(c.localVars)||(c.localVars={name:f,next:c.localVars}):a(c.globalVars)||x.globalVars&&(c.globalVars={name:f,next:c.globalVars})}function w(){l.state.context={prev:l.state.context,vars:l.state.localVars};l.state.localVars=Ca}function J(){l.state.localVars=l.state.context.vars;l.state.context=
+l.state.context.prev}function v(f,a){var c=function(){var c=l.state,e=c.indented;if("stat"==c.lexical.type)e=c.lexical.indented;else for(var b=c.lexical;b&&")"==b.type&&b.align;b=b.prev)e=b.indented;c.lexical=new C(e,l.stream.column(),f,null,c.lexical,a)};return c.lex=!0,c}function r(){var f=l.state;f.lexical.prev&&(")"==f.lexical.type&&(f.indented=f.lexical.indented),f.lexical=f.lexical.prev)}function h(f){function c(e){return e==f?a():";"==f?g():a(c)}return c}function D(f,e){return"var"==f?a(v("vardef",
+e.length),z,h(";"),r):"keyword a"==f?a(v("form"),R,D,r):"keyword b"==f?a(v("form"),D,r):"{"==f?a(v("}"),X,r):";"==f?a():"if"==f?("else"==l.state.lexical.info&&l.state.cc[l.state.cc.length-1]==r&&l.state.cc.pop()(),a(v("form"),R,D,r,ra)):"function"==f?a(N):"for"==f?a(v("form"),Da,D,r):"variable"==f?L&&"type"==e?(l.marked="keyword",a(I,h("operator"),I,h(";"))):a(v("stat"),Ea):"switch"==f?a(v("form"),R,h("{"),v("}","switch"),X,r,r):"case"==f?a(u,h(":")):"default"==f?a(h(":")):"catch"==f?a(v("form"),
+w,h("("),la,h(")"),D,r,J):"class"==f?a(v("form"),sa,r):"export"==f?a(v("stat"),Fa,r):"import"==f?a(v("stat"),Ga,r):"module"==f?a(v("form"),c,h("{"),v("}"),X,r,r):"async"==f?a(D):"@"==e?a(u,D):g(v("stat"),u,h(";"),r)}function u(f){return G(f,!1)}function m(f){return G(f,!0)}function R(f){return"("!=f?g():a(v(")"),u,h(")"),r)}function G(f,e){if(l.state.fatArrowAt==l.stream.start){var b=e?pa:H;if("("==f)return a(w,v(")"),O(c,")"),r,h("\x3d\x3e"),b,J);if("variable"==f)return g(w,c,h("\x3d\x3e"),b,J)}b=
+e?F:K;return Ha.hasOwnProperty(f)?a(b):"function"==f?a(N,b):"class"==f?a(v("form"),Ia,r):"keyword c"==f||"async"==f?a(e?P:W):"("==f?a(v(")"),W,h(")"),r,b):"operator"==f||"spread"==f?a(e?m:u):"["==f?a(v("]"),Ja,r,b):"{"==f?Q(ma,"}",null,b):"quasi"==f?g(ba,b):"new"==f?a(za(e)):a()}function W(f){return f.match(/[;\}\)\],]/)?g():g(u)}function P(f){return f.match(/[;\}\)\],]/)?g():g(m)}function K(f,c){return","==f?a(u):F(f,c,!1)}function F(f,c,e){var b=0==e?K:F,d=0==e?u:m;return"\x3d\x3e"==f?a(w,e?pa:
+H,J):"operator"==f?/\+\+|--/.test(c)?a(b):"?"==c?a(u,h(":"),d):a(d):"quasi"==f?g(ba,b):";"!=f?"("==f?Q(m,")","call",b):"."==f?a(Ka,b):"["==f?a(v("]"),W,h("]"),r,b):L&&"as"==c?(l.marked="keyword",a(I,b)):void 0:void 0}function ba(f,c){return"quasi"!=f?g():"${"!=c.slice(c.length-2)?a(ba):a(u,xa)}function xa(f){if("}"==f)return l.marked="string-2",l.state.tokenize=k,a(ba)}function H(f){return y(l.stream,l.state),g("{"==f?D:u)}function pa(f){return y(l.stream,l.state),g("{"==f?D:m)}function za(f){return function(c){return"."==
+c?a(f?La:ya):g(f?m:u)}}function ya(f,c){if("target"==c)return l.marked="keyword",a(K)}function La(f,c){if("target"==c)return l.marked="keyword",a(F)}function Ea(f){return":"==f?a(r,D):g(K,h(";"),r)}function Ka(f){if("variable"==f)return l.marked="property",a()}function ma(f,c){return"async"==f?(l.marked="property",a(ma)):"variable"==f||"keyword"==l.style?(l.marked="property",a("get"==c||"set"==c?Ma:S)):"number"==f||"string"==f?(l.marked=ea?"property":l.style+" property",a(S)):"jsonld-keyword"==f?
+a(S):"modifier"==f?a(ma):"["==f?a(u,h("]"),S):"spread"==f?a(u,S):":"==f?g(S):void 0}function Ma(f){return"variable"!=f?g(S):(l.marked="property",a(N))}function S(f){return":"==f?a(m):"("==f?g(N):void 0}function O(f,c,e){function b(d,t){if(e?-1<e.indexOf(d):","==d){var m=l.state.lexical;return"call"==m.info&&(m.pos=(m.pos||0)+1),a(function(a,e){return a==c||e==c?g():g(f)},b)}return d==c||t==c?a():a(h(c))}return function(e,d){return e==c||d==c?a():g(f,b)}}function Q(f,c,e){for(var b=3;b<arguments.length;b++)l.cc.push(arguments[b]);
+return a(v(c,e),O(f,c),r)}function X(f){return"}"==f?a():g(D,X)}function T(f,c){if(L){if(":"==f)return a(I);if("?"==c)return a(T)}}function I(c){return"variable"==c?(l.marked="type",a(U)):"string"==c||"number"==c||"atom"==c?a(U):"{"==c?a(v("}"),O(M,"}",",;"),r,U):"("==c?a(O(fa,")"),ga):void 0}function ga(c){if("\x3d\x3e"==c)return a(I)}function M(c,e){return"variable"==c||"keyword"==l.style?(l.marked="property",a(M)):"?"==e?a(M):":"==c?a(I):"["==c?a(u,T,h("]"),M):void 0}function fa(c){return"variable"==
+c?a(fa):":"==c?a(I):void 0}function U(c,e){return"\x3c"==e?a(v("\x3e"),O(I,"\x3e"),r,U):"|"==e||"."==c?a(I):"["==c?a(h("]"),U):"extends"==e?a(I):void 0}function z(){return g(c,T,e,Na)}function c(f,e){return"modifier"==f?a(c):"variable"==f?(E(e),a()):"spread"==f?a(c):"["==f?Q(c,"]"):"{"==f?Q(t,"}"):void 0}function t(f,b){return"variable"!=f||l.stream.match(/^\s*:/,!1)?("variable"==f&&(l.marked="property"),"spread"==f?a(c):"}"==f?g():a(h(":"),c,e)):(E(b),a(e))}function e(c,e){if("\x3d"==e)return a(m)}
+function Na(c){if(","==c)return a(z)}function ra(c,e){if("keyword b"==c&&"else"==e)return a(v("form","else"),D,r)}function Da(c){if("("==c)return a(v(")"),Oa,h(")"),r)}function Oa(c){return"var"==c?a(z,h(";"),ha):";"==c?a(ha):"variable"==c?a(Pa):g(u,h(";"),ha)}function Pa(c,e){return"in"==e||"of"==e?(l.marked="keyword",a(u)):a(K,ha)}function ha(c,e){return";"==c?a(ta):"in"==e||"of"==e?(l.marked="keyword",a(u)):g(u,h(";"),ta)}function ta(c){")"!=c&&a(u)}function N(c,e){return"*"==e?(l.marked="keyword",
+a(N)):"variable"==c?(E(e),a(N)):"("==c?a(w,v(")"),O(la,")"),r,T,D,J):L&&"\x3c"==e?a(v("\x3e"),O(I,"\x3e"),r,N):void 0}function la(f){return"spread"==f?a(la):g(c,T,e)}function Ia(c,a){return"variable"==c?sa(c,a):ia(c,a)}function sa(c,e){if("variable"==c)return E(e),a(ia)}function ia(c,e){return"\x3c"==e?a(v("\x3e"),O(I,"\x3e"),r,ia):"extends"==e||"implements"==e||L&&","==c?a(L?I:u,ia):"{"==c?a(v("}"),V,r):void 0}function V(c,e){return"variable"==c||"keyword"==l.style?("async"==e||"static"==e||"get"==
+e||"set"==e||L&&("public"==e||"private"==e||"protected"==e||"readonly"==e||"abstract"==e))&&l.stream.match(/^\s+[\w$\xa1-\uffff]/,!1)?(l.marked="keyword",a(V)):(l.marked="property",a(L?na:N,V)):"["==c?a(u,h("]"),L?na:N,V):"*"==e?(l.marked="keyword",a(V)):";"==c?a(V):"}"==c?a():"@"==e?a(u,V):void 0}function na(c,b){return"?"==b?a(na):":"==c?a(I,e):"\x3d"==b?a(m):g(N)}function Fa(c,e){return"*"==e?(l.marked="keyword",a(oa,h(";"))):"default"==e?(l.marked="keyword",a(u,h(";"))):"{"==c?a(O(ua,"}"),oa,
+h(";")):g(D)}function ua(c,e){return"as"==e?(l.marked="keyword",a(h("variable"))):"variable"==c?g(m,ua):void 0}function Ga(c){return"string"==c?a():g(ja,va,oa)}function ja(c,e){return"{"==c?Q(ja,"}"):("variable"==c&&E(e),"*"==e&&(l.marked="keyword"),a(Qa))}function va(c){if(","==c)return a(ja,va)}function Qa(c,e){if("as"==e)return l.marked="keyword",a(ja)}function oa(c,e){if("from"==e)return l.marked="keyword",a(u)}function Ja(c){return"]"==c?a():g(O(m,"]"))}var aa,ca,Y=B.indentUnit,wa=x.statementIndent,
+ea=x.jsonld,Z=x.json||ea,L=x.typescript,ka=x.wordCharacters||/[\w$\xa1-\uffff]/,qa=function(){function c(a){return{type:a,style:"keyword"}}var a=c("keyword a"),e=c("keyword b"),b=c("keyword c"),d=c("operator"),t={type:"atom",style:"atom"},a={"if":c("if"),"while":a,"with":a,"else":e,"do":e,"try":e,"finally":e,"return":b,"break":b,"continue":b,"new":c("new"),"delete":b,"throw":b,"debugger":b,"var":c("var"),"const":c("var"),let:c("var"),"function":c("function"),"catch":c("catch"),"for":c("for"),"switch":c("switch"),
+"case":c("case"),"default":c("default"),"in":d,"typeof":d,"instanceof":d,"true":t,"false":t,"null":t,undefined:t,NaN:t,Infinity:t,"this":c("this"),"class":c("class"),"super":c("atom"),yield:b,"export":c("export"),"import":c("import"),"extends":b,await:b};if(L){var e={type:"variable",style:"type"},b={"interface":c("class"),"implements":b,namespace:b,module:c("module"),"enum":c("module"),"public":c("modifier"),"private":c("modifier"),"protected":c("modifier"),"abstract":c("modifier"),string:e,number:e,
+"boolean":e,any:e},m;for(m in b)a[m]=b[m]}return a}(),da=/[+\-*&%=<>!?|~^@]/,Aa=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/,Ba="([{}])",Ha={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,"this":!0,"jsonld-keyword":!0},l={state:null,column:null,marked:null,cc:null},Ca={name:"this",next:{name:"arguments"}};return r.lex=!0,{startState:function(c){c={tokenize:n,lastType:"sof",cc:[],lexical:new C((c||0)-Y,0,"block",!1),localVars:x.localVars,context:x.localVars&&
+{vars:x.localVars},indented:c||0};return x.globalVars&&"object"==typeof x.globalVars&&(c.globalVars=x.globalVars),c},token:function(c,a){if(c.sol()&&(a.lexical.hasOwnProperty("align")||(a.lexical.align=!1),a.indented=c.indentation(),y(c,a)),a.tokenize!=A&&c.eatSpace())return null;var e=a.tokenize(c,a);if("comment"!=aa){a.lastType="operator"!=aa||"++"!=ca&&"--"!=ca?aa:"incdec";a:{var b=aa,d=ca,t=a.cc;l.state=a;l.stream=c;l.marked=null;l.cc=t;l.style=e;for(a.lexical.hasOwnProperty("align")||(a.lexical.align=
+!0);;)if((t.length?t.pop():Z?u:D)(b,d)){for(;t.length&&t[t.length-1].lex;)t.pop()();if(l.marked)e=l.marked;else{if(b="variable"==b)b:{for(b=a.localVars;b;b=b.next)if(b.name==d){b=!0;break b}for(t=a.context;t;t=t.prev)for(b=t.vars;b;b=b.next)if(b.name==d){b=!0;break b}b=void 0}e=b?"variable-2":e}break a}}}return e},indent:function(c,a){if(c.tokenize==A)return d.Pass;if(c.tokenize!=n)return 0;var e,b=a&&a.charAt(0),t=c.lexical;if(!/^\s*else\b/.test(a))for(var m=c.cc.length-1;0<=m;--m){var g=c.cc[m];
+if(g==r)t=t.prev;else if(g!=ra)break}for(;!("stat"!=t.type&&"form"!=t.type||"}"!=b&&(!(e=c.cc[c.cc.length-1])||e!=K&&e!=F||/^[,\.=+\-*:?[\(]/.test(a)));)t=t.prev;wa&&")"==t.type&&"stat"==t.prev.type&&(t=t.prev);e=t.type;m=b==e;"vardef"==e?b=t.indented+("operator"==c.lastType||","==c.lastType?t.info+1:0):"form"==e&&"{"==b?b=t.indented:"form"==e?b=t.indented+Y:"stat"==e?(b=t.indented,t="operator"==c.lastType||","==c.lastType||da.test(a.charAt(0))||/[,.]/.test(a.charAt(0)),b+=t?wa||Y:0):b="switch"!=
+t.info||m||0==x.doubleIndentSwitch?t.align?t.column+(m?0:1):t.indented+(m?0:Y):t.indented+(/^(?:case|default)\b/.test(a)?Y:2*Y);return b},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:Z?null:"/*",blockCommentEnd:Z?null:"*/",lineComment:Z?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:Z?"json":"javascript",jsonldMode:ea,jsonMode:Z,expressionAllowed:p,skipExpression:function(c){var a=c.cc[c.cc.length-1];a!=u&&a!=m||c.cc.pop()}}});d.registerHelper("wordChars",
+"javascript",/[\w$]/);d.defineMIME("text/javascript","javascript");d.defineMIME("text/ecmascript","javascript");d.defineMIME("application/javascript","javascript");d.defineMIME("application/x-javascript","javascript");d.defineMIME("application/ecmascript","javascript");d.defineMIME("application/json",{name:"javascript",json:!0});d.defineMIME("application/x-json",{name:"javascript",json:!0});d.defineMIME("application/ld+json",{name:"javascript",jsonld:!0});d.defineMIME("text/typescript",{name:"javascript",
+typescript:!0});d.defineMIME("application/typescript",{name:"javascript",typescript:!0})});
+(function(d){"object"==typeof exports&&"object"==typeof module?d(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("mode/css/css",["../../lib/codemirror"],d):d(CodeMirror)})(function(d){function p(a){for(var b={},d=0;d<a.length;++d)b[a[d].toLowerCase()]=!0;return b}function B(a,b){for(var d,g=!1;null!=(d=a.next());){if(g&&"/"==d){b.tokenize=null;break}g="*"==d}return["comment","comment"]}d.defineMode("css",function(a,b){function g(c,a){var e=c.next();if(y[e]){var b=y[e](c,
+a);if(!1!==b)return b}"@"==e?(c.eatWhile(/[\w\\\-]/),e=(w=c.current(),"def")):e="\x3d"==e||("~"==e||"|"==e)&&c.eat("\x3d")?(w="compare",null):'"'==e||"'"==e?(a.tokenize=q(e),a.tokenize(c,a)):"#"==e?(c.eatWhile(/[\w\\\-]/),w="hash","atom"):"!"==e?(c.match(/^\s*\w*/),w="important","keyword"):/\d/.test(e)||"."==e&&c.eat(/\d/)?(c.eatWhile(/[\w.%]/),w="unit","number"):"-"!==e?/[,+>*\/]/.test(e)?(w="select-op",null):"."==e&&c.match(/^-?[_a-z][_a-z0-9-]*/i)?(w="qualifier","qualifier"):/[:;{}\[\]\(\)]/.test(e)?
+(w=e,null):"u"==e&&c.match(/rl(-prefix)?\(/)||"d"==e&&c.match("omain(")||"r"==e&&c.match("egexp(")?(c.backUp(1),a.tokenize=n,w="word","property"):/[\w\\\-]/.test(e)?(c.eatWhile(/[\w\\\-]/),w="word","property"):(w=null,null):/[\d.]/.test(c.peek())?(c.eatWhile(/[\w.%]/),w="unit","number"):c.match(/^-[\w\\\-]+/)?(c.eatWhile(/[\w\\\-]/),c.match(/^\s*:/,!1)?(w="variable-definition","variable-2"):(w="variable","variable-2")):c.match(/^\w+-/)?(w="meta","meta"):void 0;return e}function q(c){return function(a,
+e){for(var b,d=!1;null!=(b=a.next());){if(b==c&&!d){")"==c&&a.backUp(1);break}d=!d&&"\\"==b}return(b==c||!d&&")"!=c)&&(e.tokenize=null),w="string","string"}}function n(c,a){return c.next(),c.match(/\s*[\"\')]/,!1)?a.tokenize=null:a.tokenize=q(")"),w="(",null}function r(c,a,e){this.type=c;this.indent=a;this.prev=e}function h(c,a,e,b){return c.context=new r(e,a.indentation()+(!1===b?0:p),c.context),e}function u(c){return c.context.prev&&(c.context=c.context.prev),c.context.type}function E(c,a,e,b){for(b=
+b||1;0<b;b--)e.context=e.context.prev;return z[e.context.type](c,a,e)}function v(c){c=c.current().toLowerCase();k=ga.hasOwnProperty(c)?"atom":I.hasOwnProperty(c)?"keyword":"variable"}var A=b.inline;b.propertyKeywords||(b=d.resolveMode("text/css"));var w,k,p=a.indentUnit,y=b.tokenHooks,x=b.documentTypes||{},C=b.mediaTypes||{},B=b.mediaFeatures||{},J=b.mediaValueKeywords||{},D=b.propertyKeywords||{},Q=b.nonStandardPropertyKeywords||{},X=b.fontProperties||{},T=b.counterDescriptors||{},I=b.colorKeywords||
+{},ga=b.valueKeywords||{},M=b.allowNested,fa=b.lineComment,U=!0===b.supportsAtComponent,z={};return z.top=function(c,a,b){if("{"==c)return h(b,a,"block");if("}"==c&&b.context.prev)return u(b);if(U&&/@component/.test(c))return h(b,a,"atComponentBlock");if(/^@(-moz-)?document$/.test(c))return h(b,a,"documentTypes");if(/^@(media|supports|(-moz-)?document|import)$/.test(c))return h(b,a,"atBlock");if(/^@(font-face|counter-style)/.test(c))return b.stateArg=c,"restricted_atBlock_before";if(/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(c))return"keyframes";
+if(c&&"@"==c.charAt(0))return h(b,a,"at");if("hash"==c)k="builtin";else if("word"==c)k="tag";else{if("variable-definition"==c)return"maybeprop";if("interpolation"==c)return h(b,a,"interpolation");if(":"==c)return"pseudo";if(M&&"("==c)return h(b,a,"parens")}return b.context.type},z.block=function(c,a,b){return"word"==c?(c=a.current().toLowerCase(),D.hasOwnProperty(c)?(k="property","maybeprop"):Q.hasOwnProperty(c)?(k="string-2","maybeprop"):M?(k=a.match(/^\s*:(?:\s|$)/,!1)?"property":"tag","block"):
+(k+=" error","maybeprop")):"meta"==c?"block":M||"hash"!=c&&"qualifier"!=c?z.top(c,a,b):(k="error","block")},z.maybeprop=function(c,a,b){return":"==c?h(b,a,"prop"):z[b.context.type](c,a,b)},z.prop=function(c,a,b){if(";"==c)return u(b);if("{"==c&&M)return h(b,a,"propBlock");if("}"==c||"{"==c)return E(c,a,b);if("("==c)return h(b,a,"parens");if("hash"!=c||/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(a.current()))if("word"==c)v(a);else{if("interpolation"==c)return h(b,a,"interpolation")}else k+=
+" error";return"prop"},z.propBlock=function(c,a,b){return"}"==c?u(b):"word"==c?(k="property","maybeprop"):b.context.type},z.parens=function(c,a,b){return"{"==c||"}"==c?E(c,a,b):")"==c?u(b):"("==c?h(b,a,"parens"):"interpolation"==c?h(b,a,"interpolation"):("word"==c&&v(a),"parens")},z.pseudo=function(c,a,b){return"meta"==c?"pseudo":"word"==c?(k="variable-3",b.context.type):z[b.context.type](c,a,b)},z.documentTypes=function(c,a,b){return"word"==c&&x.hasOwnProperty(a.current())?(k="tag",b.context.type):
+z.atBlock(c,a,b)},z.atBlock=function(c,a,b){if("("==c)return h(b,a,"atBlock_parens");if("}"==c||";"==c)return E(c,a,b);if("{"==c)return u(b)&&h(b,a,M?"block":"top");if("interpolation"==c)return h(b,a,"interpolation");"word"==c&&(c=a.current().toLowerCase(),k="only"==c||"not"==c||"and"==c||"or"==c?"keyword":C.hasOwnProperty(c)?"attribute":B.hasOwnProperty(c)?"property":J.hasOwnProperty(c)?"keyword":D.hasOwnProperty(c)?"property":Q.hasOwnProperty(c)?"string-2":ga.hasOwnProperty(c)?"atom":I.hasOwnProperty(c)?
+"keyword":"error");return b.context.type},z.atComponentBlock=function(c,a,b){return"}"==c?E(c,a,b):"{"==c?u(b)&&h(b,a,M?"block":"top",!1):("word"==c&&(k="error"),b.context.type)},z.atBlock_parens=function(c,a,b){return")"==c?u(b):"{"==c||"}"==c?E(c,a,b,2):z.atBlock(c,a,b)},z.restricted_atBlock_before=function(c,a,b){return"{"==c?h(b,a,"restricted_atBlock"):"word"==c&&"@counter-style"==b.stateArg?(k="variable","restricted_atBlock_before"):z[b.context.type](c,a,b)},z.restricted_atBlock=function(c,a,
+b){return"}"==c?(b.stateArg=null,u(b)):"word"==c?(k="@font-face"==b.stateArg&&!X.hasOwnProperty(a.current().toLowerCase())||"@counter-style"==b.stateArg&&!T.hasOwnProperty(a.current().toLowerCase())?"error":"property","maybeprop"):"restricted_atBlock"},z.keyframes=function(c,a,b){return"word"==c?(k="variable","keyframes"):"{"==c?h(b,a,"top"):z[b.context.type](c,a,b)},z.at=function(c,a,b){return";"==c?u(b):"{"==c||"}"==c?E(c,a,b):("word"==c?k="tag":"hash"==c&&(k="builtin"),"at")},z.interpolation=function(c,
+a,b){return"}"==c?u(b):"{"==c||";"==c?E(c,a,b):("word"==c?k="variable":"variable"!=c&&"("!=c&&")"!=c&&(k="error"),"interpolation")},{startState:function(c){return{tokenize:null,state:A?"block":"top",stateArg:null,context:new r(A?"block":"top",c||0,null)}},token:function(c,a){if(!a.tokenize&&c.eatSpace())return null;var b=(a.tokenize||g)(c,a);return b&&"object"==typeof b&&(w=b[1],b=b[0]),k=b,a.state=z[a.state](w,c,a),k},indent:function(c,a){var b=c.context,d=a&&a.charAt(0),m=b.indent;return"prop"!=
+b.type||"}"!=d&&")"!=d||(b=b.prev),b.prev&&("}"!=d||"block"!=b.type&&"top"!=b.type&&"interpolation"!=b.type&&"restricted_atBlock"!=b.type?(")"!=d||"parens"!=b.type&&"atBlock_parens"!=b.type)&&("{"!=d||"at"!=b.type&&"atBlock"!=b.type)||(m=Math.max(0,b.indent-p)):(b=b.prev,m=b.indent)),m},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",lineComment:fa,fold:"brace"}});var x=["domain","regexp","url","url-prefix"],b=p(x),n="all aural braille handheld print projection screen tty tv embossed".split(" "),
+q=p(n),A="width min-width max-width height min-height max-height device-width min-device-width max-device-width device-height min-device-height max-device-height aspect-ratio min-aspect-ratio max-aspect-ratio device-aspect-ratio min-device-aspect-ratio max-device-aspect-ratio color min-color max-color color-index min-color-index max-color-index monochrome min-monochrome max-monochrome resolution min-resolution max-resolution scan grid orientation device-pixel-ratio min-device-pixel-ratio max-device-pixel-ratio pointer any-pointer hover any-hover".split(" "),
+k=p(A),y="landscape portrait none coarse fine on-demand hover interlace progressive".split(" "),C=p(y),g="align-content align-items align-self alignment-adjust alignment-baseline anchor-point animation animation-delay animation-direction animation-duration animation-fill-mode animation-iteration-count animation-name animation-play-state animation-timing-function appearance azimuth backface-visibility background background-attachment background-blend-mode background-clip background-color background-image background-origin background-position background-repeat background-size baseline-shift binding bleed bookmark-label bookmark-level bookmark-state bookmark-target border border-bottom border-bottom-color border-bottom-left-radius border-bottom-right-radius border-bottom-style border-bottom-width border-collapse border-color border-image border-image-outset border-image-repeat border-image-slice border-image-source border-image-width border-left border-left-color border-left-style border-left-width border-radius border-right border-right-color border-right-style border-right-width border-spacing border-style border-top border-top-color border-top-left-radius border-top-right-radius border-top-style border-top-width border-width bottom box-decoration-break box-shadow box-sizing break-after break-before break-inside caption-side caret-color clear clip color color-profile column-count column-fill column-gap column-rule column-rule-color column-rule-style column-rule-width column-span column-width columns content counter-increment counter-reset crop cue cue-after cue-before cursor direction display dominant-baseline drop-initial-after-adjust drop-initial-after-align drop-initial-before-adjust drop-initial-before-align drop-initial-size drop-initial-value elevation empty-cells fit fit-position flex flex-basis flex-direction flex-flow flex-grow flex-shrink flex-wrap float float-offset flow-from flow-into font font-feature-settings font-family font-kerning font-language-override font-size font-size-adjust font-stretch font-style font-synthesis font-variant font-variant-alternates font-variant-caps font-variant-east-asian font-variant-ligatures font-variant-numeric font-variant-position font-weight grid grid-area grid-auto-columns grid-auto-flow grid-auto-rows grid-column grid-column-end grid-column-gap grid-column-start grid-gap grid-row grid-row-end grid-row-gap grid-row-start grid-template grid-template-areas grid-template-columns grid-template-rows hanging-punctuation height hyphens icon image-orientation image-rendering image-resolution inline-box-align justify-content justify-items justify-self left letter-spacing line-break line-height line-stacking line-stacking-ruby line-stacking-shift line-stacking-strategy list-style list-style-image list-style-position list-style-type margin margin-bottom margin-left margin-right margin-top marks marquee-direction marquee-loop marquee-play-count marquee-speed marquee-style max-height max-width min-height min-width move-to nav-down nav-index nav-left nav-right nav-up object-fit object-position opacity order orphans outline outline-color outline-offset outline-style outline-width overflow overflow-style overflow-wrap overflow-x overflow-y padding padding-bottom padding-left padding-right padding-top page page-break-after page-break-before page-break-inside page-policy pause pause-after pause-before perspective perspective-origin pitch pitch-range place-content place-items place-self play-during position presentation-level punctuation-trim quotes region-break-after region-break-before region-break-inside region-fragment rendering-intent resize rest rest-after rest-before richness right rotation rotation-point ruby-align ruby-overhang ruby-position ruby-span shape-image-threshold shape-inside shape-margin shape-outside size speak speak-as speak-header speak-numeral speak-punctuation speech-rate stress string-set tab-size table-layout target target-name target-new target-position text-align text-align-last text-decoration text-decoration-color text-decoration-line text-decoration-skip text-decoration-style text-emphasis text-emphasis-color text-emphasis-position text-emphasis-style text-height text-indent text-justify text-outline text-overflow text-shadow text-size-adjust text-space-collapse text-transform text-underline-position text-wrap top transform transform-origin transform-style transition transition-delay transition-duration transition-property transition-timing-function unicode-bidi user-select vertical-align visibility voice-balance voice-duration voice-family voice-pitch voice-range voice-rate voice-stress voice-volume volume white-space widows width will-change word-break word-spacing word-wrap z-index clip-path clip-rule mask enable-background filter flood-color flood-opacity lighting-color stop-color stop-opacity pointer-events color-interpolation color-interpolation-filters color-rendering fill fill-opacity fill-rule image-rendering marker marker-end marker-mid marker-start shape-rendering stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-rendering baseline-shift dominant-baseline glyph-orientation-horizontal glyph-orientation-vertical text-anchor writing-mode".split(" "),
+a=p(g),E="scrollbar-arrow-color scrollbar-base-color scrollbar-dark-shadow-color scrollbar-face-color scrollbar-highlight-color scrollbar-shadow-color scrollbar-3d-light-color scrollbar-track-color shape-inside searchfield-cancel-button searchfield-decoration searchfield-results-button searchfield-results-decoration zoom".split(" "),w=p(E),J=p("font-family src unicode-range font-variant font-feature-settings font-stretch font-weight font-style".split(" ")),v=p("additive-symbols fallback negative pad prefix range speak-as suffix symbols system".split(" ")),
+r="aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkturquoise darkviolet deeppink deepskyblue dimgray dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray grey green greenyellow honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightpink lightsalmon lightseagreen lightskyblue lightslategray lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray snow springgreen steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen".split(" "),
+h=p(r),D="above absolute activeborder additive activecaption afar after-white-space ahead alias all all-scroll alphabetic alternate always amharic amharic-abegede antialiased appworkspace arabic-indic armenian asterisks attr auto auto-flow avoid avoid-column avoid-page avoid-region background backwards baseline below bidi-override binary bengali blink block block-axis bold bolder border border-box both bottom break break-all break-word bullets button button-bevel buttonface buttonhighlight buttonshadow buttontext calc cambodian capitalize caps-lock-indicator caption captiontext caret cell center checkbox circle cjk-decimal cjk-earthly-branch cjk-heavenly-stem cjk-ideographic clear clip close-quote col-resize collapse color color-burn color-dodge column column-reverse compact condensed contain content contents content-box context-menu continuous copy counter counters cover crop cross crosshair currentcolor cursive cyclic darken dashed decimal decimal-leading-zero default default-button dense destination-atop destination-in destination-out destination-over devanagari difference disc discard disclosure-closed disclosure-open document dot-dash dot-dot-dash dotted double down e-resize ease ease-in ease-in-out ease-out element ellipse ellipsis embed end ethiopic ethiopic-abegede ethiopic-abegede-am-et ethiopic-abegede-gez ethiopic-abegede-ti-er ethiopic-abegede-ti-et ethiopic-halehame-aa-er ethiopic-halehame-aa-et ethiopic-halehame-am-et ethiopic-halehame-gez ethiopic-halehame-om-et ethiopic-halehame-sid-et ethiopic-halehame-so-et ethiopic-halehame-ti-er ethiopic-halehame-ti-et ethiopic-halehame-tig ethiopic-numeric ew-resize exclusion expanded extends extra-condensed extra-expanded fantasy fast fill fixed flat flex flex-end flex-start footnotes forwards from geometricPrecision georgian graytext grid groove gujarati gurmukhi hand hangul hangul-consonant hard-light hebrew help hidden hide higher highlight highlighttext hiragana hiragana-iroha horizontal hsl hsla hue icon ignore inactiveborder inactivecaption inactivecaptiontext infinite infobackground infotext inherit initial inline inline-axis inline-block inline-flex inline-grid inline-table inset inside intrinsic invert italic japanese-formal japanese-informal justify kannada katakana katakana-iroha keep-all khmer korean-hangul-formal korean-hanja-formal korean-hanja-informal landscape lao large larger left level lighter lighten line-through linear linear-gradient lines list-item listbox listitem local logical loud lower lower-alpha lower-armenian lower-greek lower-hexadecimal lower-latin lower-norwegian lower-roman lowercase ltr luminosity malayalam match matrix matrix3d media-controls-background media-current-time-display media-fullscreen-button media-mute-button media-play-button media-return-to-realtime-button media-rewind-button media-seek-back-button media-seek-forward-button media-slider media-sliderthumb media-time-remaining-display media-volume-slider media-volume-slider-container media-volume-sliderthumb medium menu menulist menulist-button menulist-text menulist-textfield menutext message-box middle min-intrinsic mix mongolian monospace move multiple multiply myanmar n-resize narrower ne-resize nesw-resize no-close-quote no-drop no-open-quote no-repeat none normal not-allowed nowrap ns-resize numbers numeric nw-resize nwse-resize oblique octal opacity open-quote optimizeLegibility optimizeSpeed oriya oromo outset outside outside-shape overlay overline padding padding-box painted page paused persian perspective plus-darker plus-lighter pointer polygon portrait pre pre-line pre-wrap preserve-3d progress push-button radial-gradient radio read-only read-write read-write-plaintext-only rectangle region relative repeat repeating-linear-gradient repeating-radial-gradient repeat-x repeat-y reset reverse rgb rgba ridge right rotate rotate3d rotateX rotateY rotateZ round row row-resize row-reverse rtl run-in running s-resize sans-serif saturation scale scale3d scaleX scaleY scaleZ screen scroll scrollbar scroll-position se-resize searchfield searchfield-cancel-button searchfield-decoration searchfield-results-button searchfield-results-decoration self-start self-end semi-condensed semi-expanded separate serif show sidama simp-chinese-formal simp-chinese-informal single skew skewX skewY skip-white-space slide slider-horizontal slider-vertical sliderthumb-horizontal sliderthumb-vertical slow small small-caps small-caption smaller soft-light solid somali source-atop source-in source-out source-over space space-around space-between space-evenly spell-out square square-button start static status-bar stretch stroke sub subpixel-antialiased super sw-resize symbolic symbols system-ui table table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group tamil telugu text text-bottom text-top textarea textfield thai thick thin threeddarkshadow threedface threedhighlight threedlightshadow threedshadow tibetan tigre tigrinya-er tigrinya-er-abegede tigrinya-et tigrinya-et-abegede to top trad-chinese-formal trad-chinese-informal transform translate translate3d translateX translateY translateZ transparent ultra-condensed ultra-expanded underline unset up upper-alpha upper-armenian upper-greek upper-hexadecimal upper-latin upper-norwegian upper-roman uppercase urdu url var vertical vertical-text visible visibleFill visiblePainted visibleStroke visual w-resize wait wave wider window windowframe windowtext words wrap wrap-reverse x-large x-small xor xx-large xx-small".split(" "),
+u=p(D),x=x.concat(n).concat(A).concat(y).concat(g).concat(E).concat(r).concat(D);d.registerHelper("hintWords","css",x);d.defineMIME("text/css",{documentTypes:b,mediaTypes:q,mediaFeatures:k,mediaValueKeywords:C,propertyKeywords:a,nonStandardPropertyKeywords:w,fontProperties:J,counterDescriptors:v,colorKeywords:h,valueKeywords:u,tokenHooks:{"/":function(a,b){return!!a.eat("*")&&(b.tokenize=B,B(a,b))}},name:"css"});d.defineMIME("text/x-scss",{mediaTypes:q,mediaFeatures:k,mediaValueKeywords:C,propertyKeywords:a,
+nonStandardPropertyKeywords:w,colorKeywords:h,valueKeywords:u,fontProperties:J,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(a,b){return a.eat("/")?(a.skipToEnd(),["comment","comment"]):a.eat("*")?(b.tokenize=B,B(a,b)):["operator","operator"]},":":function(a){return!!a.match(/\s*\{/,!1)&&[null,null]},$:function(a){return a.match(/^[\w-]+/),a.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"#":function(a){return!!a.eat("{")&&[null,"interpolation"]}},name:"css",
+helperType:"scss"});d.defineMIME("text/x-less",{mediaTypes:q,mediaFeatures:k,mediaValueKeywords:C,propertyKeywords:a,nonStandardPropertyKeywords:w,colorKeywords:h,valueKeywords:u,fontProperties:J,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(a,b){return a.eat("/")?(a.skipToEnd(),["comment","comment"]):a.eat("*")?(b.tokenize=B,B(a,b)):["operator","operator"]},"@":function(a){return a.eat("{")?[null,"interpolation"]:!a.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/,
+!1)&&(a.eatWhile(/[\w\\\-]/),a.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"])},"\x26":function(){return["atom","atom"]}},name:"css",helperType:"less"});d.defineMIME("text/x-gss",{documentTypes:b,mediaTypes:q,mediaFeatures:k,propertyKeywords:a,nonStandardPropertyKeywords:w,fontProperties:J,counterDescriptors:v,colorKeywords:h,valueKeywords:u,supportsAtComponent:!0,tokenHooks:{"/":function(a,b){return!!a.eat("*")&&(b.tokenize=B,B(a,b))}},name:"css",helperType:"gss"})});
+(function(d){"object"==typeof exports&&"object"==typeof module?d(require("../../lib/codemirror"),require("../xml/xml"),require("../javascript/javascript"),require("../css/css")):"function"==typeof define&&define.amd?define("mode/htmlmixed/htmlmixed",["../../lib/codemirror","../xml/xml","../javascript/javascript","../css/css"],d):d(CodeMirror)})(function(d){function p(b,d){var k=b.match(n[d]||(n[d]=new RegExp("\\s+"+d+"\\s*\x3d\\s*('|\")?([^'\"]+)('|\")?\\s*")));return k?/^\s*(.*?)\s*$/.exec(k[2])[1]:
+""}function B(b,d){for(var k in b)for(var n=d[k]||(d[k]=[]),p=b[k],g=p.length-1;0<=g;g--)n.unshift(p[g])}function x(b,d){for(var k=0;k<b.length;k++){var n=b[k];if(!n[0]||n[1].test(p(d,n[0])))return n[2]}}var b={script:[["lang",/(javascript|babel)/i,"javascript"],["type",/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i,"javascript"],["type",/./,"text/plain"],[null,null,"javascript"]],style:[["lang",/^css$/i,"css"],["type",/^(text\/)?(x-)?(stylesheet|css)$/i,"css"],["type",/./,"text/plain"],
+[null,null,"css"]]},n={};d.defineMode("htmlmixed",function(n,p){function k(a,b){var g,p=y.token(a,b.htmlState),r=/\btag\b/.test(p);if(r&&!/[<>\s\/]/.test(a.current())&&(g=b.htmlState.tagName&&b.htmlState.tagName.toLowerCase())&&C.hasOwnProperty(g))b.inTag=g+" ";else if(b.inTag&&r&&/>$/.test(a.current())){g=/^([\S]+) (.*)/.exec(b.inTag);b.inTag=null;var r="\x3e"==a.current()&&x(C[g[1]],g[2]),r=d.getMode(n,r),h=new RegExp("^\x3c/s*"+g[1]+"s*\x3e","i"),A=new RegExp("\x3c/s*"+g[1]+"s*\x3e","i");b.token=
+function(a,b){var d;if(a.match(h,!1))d=(b.token=k,b.localState=b.localMode=null,null);else{d=b.localMode.token(a,b.localState);var g=a.current(),n=g.search(A);d=(-1<n?a.backUp(g.length-n):g.match(/<\/?$/)&&(a.backUp(g.length),a.match(A,!1)||a.match(g)),d)}return d};b.localMode=r;b.localState=d.startState(r,y.indent(b.htmlState,""))}else b.inTag&&(b.inTag+=a.current(),a.eol()&&(b.inTag+=" "));return p}var y=d.getMode(n,{name:"xml",htmlMode:!0,multilineTagIndentFactor:p.multilineTagIndentFactor,multilineTagIndentPastTag:p.multilineTagIndentPastTag}),
+C={},g=p&&p.tags,a=p&&p.scriptTypes;if(B(b,C),g&&B(g,C),a)for(g=a.length-1;0<=g;g--)C.script.unshift(["type",a[g].matches,a[g].mode]);return{startState:function(){return{token:k,inTag:null,localMode:null,localState:null,htmlState:d.startState(y)}},copyState:function(a){var b;return a.localState&&(b=d.copyState(a.localMode,a.localState)),{token:a.token,inTag:a.inTag,localMode:a.localMode,localState:b,htmlState:d.copyState(y,a.htmlState)}},token:function(a,b){return b.token(a,b)},indent:function(a,
+b,g){return!a.localMode||/^\s*<\//.test(b)?y.indent(a.htmlState,b):a.localMode.indent?a.localMode.indent(a.localState,b,g):d.Pass},innerMode:function(a){return{state:a.localState||a.htmlState,mode:a.localMode||y}}}},"xml","javascript","css");d.defineMIME("text/html","htmlmixed")});
+(function(d){"object"==typeof exports&&"object"==typeof module?d(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/mode/multiplex",["../../lib/codemirror"],d):d(CodeMirror)})(function(d){d.multiplexingMode=function(p){function B(b,d,q,p){return"string"==typeof d?(q=b.indexOf(d,q),p&&-1<q?q+d.length:q):(d=d.exec(q?b.slice(q):b))?d.index+q+(p?d[0].length:0):-1}var x=Array.prototype.slice.call(arguments,1);return{startState:function(){return{outer:d.startState(p),innerActive:null,
+inner:null}},copyState:function(b){return{outer:d.copyState(p,b.outer),innerActive:b.innerActive,inner:b.innerActive&&d.copyState(b.innerActive.mode,b.inner)}},token:function(b,n){if(n.innerActive){var q=n.innerActive,A=b.string;if(!q.close&&b.sol())return n.innerActive=n.inner=null,this.token(b,n);var k=q.close?B(A,q.close,b.pos,q.parseDelimiters):-1;if(k==b.pos&&!q.parseDelimiters)return b.match(q.close),n.innerActive=n.inner=null,q.delimStyle&&q.delimStyle+" "+q.delimStyle+"-close";-1<k&&(b.string=
+A.slice(0,k));var y=q.mode.token(b,n.inner);return-1<k&&(b.string=A),k==b.pos&&q.parseDelimiters&&(n.innerActive=n.inner=null),q.innerStyle&&(y=y?y+" "+q.innerStyle:q.innerStyle),y}q=1/0;A=b.string;for(y=0;y<x.length;++y){var C=x[y],k=B(A,C.open,b.pos);if(k==b.pos)return C.parseDelimiters||b.match(C.open),n.innerActive=C,n.inner=d.startState(C.mode,p.indent?p.indent(n.outer,""):0),C.delimStyle&&C.delimStyle+" "+C.delimStyle+"-open";-1!=k&&k<q&&(q=k)}q!=1/0&&(b.string=A.slice(0,q));k=p.token(b,n.outer);
+return q!=1/0&&(b.string=A),k},indent:function(b,n){var q=b.innerActive?b.innerActive.mode:p;return q.indent?q.indent(b.innerActive?b.inner:b.outer,n):d.Pass},blankLine:function(b){var n=b.innerActive?b.innerActive.mode:p;if(n.blankLine&&n.blankLine(b.innerActive?b.inner:b.outer),b.innerActive)"\n"===b.innerActive.close&&(b.innerActive=b.inner=null);else for(var q=0;q<x.length;++q){var A=x[q];"\n"===A.open&&(b.innerActive=A,b.inner=d.startState(A.mode,n.indent?n.indent(b.outer,""):0))}},electricChars:p.electricChars,
+innerMode:function(b){return b.inner?{state:b.inner,mode:b.innerActive.mode}:{state:b.outer,mode:p}}}}});
+(function(d){"object"==typeof exports&&"object"==typeof module?d(require("../../lib/codemirror"),require("../htmlmixed/htmlmixed"),require("../../addon/mode/multiplex")):"function"==typeof define&&define.amd?define("mode/htmlembedded/htmlembedded.js",["../../lib/codemirror","../htmlmixed/htmlmixed","../../addon/mode/multiplex"],d):d(CodeMirror)})(function(d){d.defineMode("htmlembedded",function(p,B){return d.multiplexingMode(d.getMode(p,"htmlmixed"),{open:B.open||B.scriptStartRegex||"\x3c%",close:B.close||
+B.scriptEndRegex||"%\x3e",mode:d.getMode(p,B.scriptingModeSpec)})},"htmlmixed");d.defineMIME("application/x-ejs",{name:"htmlembedded",scriptingModeSpec:"javascript"});d.defineMIME("application/x-aspx",{name:"htmlembedded",scriptingModeSpec:"text/x-csharp"});d.defineMIME("application/x-jsp",{name:"htmlembedded",scriptingModeSpec:"text/x-java"});d.defineMIME("application/x-erb",{name:"htmlembedded",scriptingModeSpec:"ruby"})});
+(function(d){"function"==typeof define&&define("modeHtml",["mode/htmlembedded/htmlembedded.js"],function(){})})();
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/js/codemirror.mode.javascript.min.js b/js/ckeditor/plugins/codemirror/js/codemirror.mode.javascript.min.js
new file mode 100644 (file)
index 0000000..4b4ff98
--- /dev/null
@@ -0,0 +1,29 @@
+!function(p){"object"==typeof exports&&"object"==typeof module?p(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("mode/javascript/javascript.js",["../../lib/codemirror"],p):p(CodeMirror)}(function(p){function ka(p,r,q){return/^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(r.lastType)||"quasi"==r.lastType&&/\{\s*$/.test(p.string.slice(0,p.pos-(q||0)))}p.defineMode("javascript",function(xa,r){function q(a,c,b){return H=a,Q=b,c}function D(a,c){var b=
+a.next();if('"'==b||"'"==b)return c.tokenize=ya(b),c.tokenize(a,c);if("."==b&&a.match(/^\d+(?:[eE][+\-]?\d+)?/))return q("number","number");if("."==b&&a.match(".."))return q("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(b))return q(b);if("\x3d"==b&&a.eat("\x3e"))return q("\x3d\x3e","operator");if("0"==b&&a.eat(/x/i))return a.eatWhile(/[\da-f]/i),q("number","number");if("0"==b&&a.eat(/o/i))return a.eatWhile(/[0-7]/i),q("number","number");if("0"==b&&a.eat(/b/i))return a.eatWhile(/[01]/i),q("number",
+"number");if(/\d/.test(b))return a.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),q("number","number");if("/"==b){if(a.eat("*"))b=(c.tokenize=R,R(a,c));else if(a.eat("/"))b=(a.skipToEnd(),q("comment","comment"));else if(ka(a,c,1)){a:for(var e=!1,d=!1;null!=(b=a.next());){if(!e){if("/"==b&&!d)break a;"["==b?d=!0:d&&"]"==b&&(d=!1)}e=!e&&"\\"==b}b=(a.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/),q("regexp","string-2"))}else b=(a.eatWhile(S),q("operator","operator",a.current()));return b}if("`"==b)return c.tokenize=
+aa,aa(a,c);if("#"==b)return a.skipToEnd(),q("error","error");if(S.test(b))return"\x3e"==b&&c.lexical&&"\x3e"==c.lexical.type||a.eatWhile(S),q("operator","operator",a.current());if(ba.test(b)){a.eatWhile(ba);b=a.current();if("."!=c.lastType){if(la.propertyIsEnumerable(b))return e=la[b],q(e.type,e.style,b);if("async"==b&&a.match(/^\s*[\(\w]/,!1))return q("async","keyword",b)}return q("variable","variable",b)}}function ya(a){return function(c,b){var e,d=!1;if(T&&"@"==c.peek()&&c.match(za))return b.tokenize=
+D,q("jsonld-keyword","meta");for(;null!=(e=c.next())&&(e!=a||d);)d=!d&&"\\"==e;return d||(b.tokenize=D),q("string","string")}}function R(a,b){for(var f,e=!1;f=a.next();){if("/"==f&&e){b.tokenize=D;break}e="*"==f}return q("comment","comment")}function aa(a,b){for(var f,e=!1;null!=(f=a.next());){if(!e&&("`"==f||"$"==f&&a.eat("{"))){b.tokenize=D;break}e=!e&&"\\"==f}return q("quasi","string-2",a.current())}function ca(a,b){b.fatArrowAt&&(b.fatArrowAt=null);var f=a.string.indexOf("\x3d\x3e",a.start);if(!(0>
+f)){if(w){var e=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(a.string.slice(a.start,f));e&&(f=e.index)}for(var e=0,d=!1,f=f-1;0<=f;--f){var k=a.string.charAt(f),h=Aa.indexOf(k);if(0<=h&&3>h){if(!e){++f;break}if(0==--e){"("==k&&(d=!0);break}}else if(3<=h&&6>h)++e;else if(ba.test(k))d=!0;else{if(/["'\/]/.test(k))return;if(d&&!e){++f;break}}}d&&!e&&(b.fatArrowAt=f)}}function ma(a,b,d,e,A,k){this.indented=a;this.column=b;this.type=d;this.prev=A;this.info=k;null!=e&&(this.align=e)}function g(){for(var a=
+arguments.length-1;0<=a;a--)d.cc.push(arguments[a])}function b(){return g.apply(null,arguments),!0}function I(a){function b(c){for(;c;c=c.next)if(c.name==a)return!0;return!1}var f=d.state;(d.marked="def",f.context)?b(f.localVars)||(f.localVars={name:a,next:f.localVars}):b(f.globalVars)||r.globalVars&&(f.globalVars={name:a,next:f.globalVars})}function J(){d.state.context={prev:d.state.context,vars:d.state.localVars};d.state.localVars=Ba}function K(){d.state.localVars=d.state.context.vars;d.state.context=
+d.state.context.prev}function l(a,b){var f=function(){var e=d.state,f=e.indented;if("stat"==e.lexical.type)f=e.lexical.indented;else for(var k=e.lexical;k&&")"==k.type&&k.align;k=k.prev)f=k.indented;e.lexical=new ma(f,d.stream.column(),a,null,e.lexical,b)};return f.lex=!0,f}function h(){var a=d.state;a.lexical.prev&&(")"==a.lexical.type&&(a.indented=a.lexical.indented),a.lexical=a.lexical.prev)}function m(a){function c(d){return d==a?b():";"==a?g():b(c)}return c}function t(a,c){return"var"==a?b(l("vardef",
+c.length),da,m(";"),h):"keyword a"==a?b(l("form"),ea,t,h):"keyword b"==a?b(l("form"),t,h):"{"==a?b(l("}"),U,h):";"==a?b():"if"==a?("else"==d.state.lexical.info&&d.state.cc[d.state.cc.length-1]==h&&d.state.cc.pop()(),b(l("form"),ea,t,h,na)):"function"==a?b(x):"for"==a?b(l("form"),Ca,t,h):"variable"==a?w&&"type"==c?(d.marked="keyword",b(u,m("operator"),u,m(";"))):b(l("stat"),Da):"switch"==a?b(l("form"),ea,m("{"),l("}","switch"),U,h,h):"case"==a?b(n,m(":")):"default"==a?b(m(":")):"catch"==a?b(l("form"),
+J,m("("),fa,m(")"),t,h,K):"class"==a?b(l("form"),oa,h):"export"==a?b(l("stat"),Ea,h):"import"==a?b(l("stat"),Fa,h):"module"==a?b(l("form"),y,m("{"),l("}"),U,h,h):"async"==a?b(t):"@"==c?b(n,t):g(l("stat"),n,m(";"),h)}function n(a){return pa(a,!1)}function v(a){return pa(a,!0)}function ea(a){return"("!=a?g():b(l(")"),n,m(")"),h)}function pa(a,c){if(d.state.fatArrowAt==d.stream.start){var f=c?qa:ra;if("("==a)return b(J,l(")"),z(y,")"),h,m("\x3d\x3e"),f,K);if("variable"==a)return g(J,y,m("\x3d\x3e"),
+f,K)}f=c?L:E;return Ga.hasOwnProperty(a)?b(f):"function"==a?b(x,f):"class"==a?b(l("form"),Ha,h):"keyword c"==a||"async"==a?b(c?Ia:ga):"("==a?b(l(")"),ga,m(")"),h,f):"operator"==a||"spread"==a?b(c?v:n):"["==a?b(l("]"),Ja,h,f):"{"==a?M(ha,"}",null,f):"quasi"==a?g(V,f):"new"==a?b(Ka(c)):b()}function ga(a){return a.match(/[;\}\)\],]/)?g():g(n)}function Ia(a){return a.match(/[;\}\)\],]/)?g():g(v)}function E(a,c){return","==a?b(n):L(a,c,!1)}function L(a,c,f){var e=0==f?E:L,A=0==f?n:v;return"\x3d\x3e"==
+a?b(J,f?qa:ra,K):"operator"==a?/\+\+|--/.test(c)?b(e):"?"==c?b(n,m(":"),A):b(A):"quasi"==a?g(V,e):";"!=a?"("==a?M(v,")","call",e):"."==a?b(La,e):"["==a?b(l("]"),ga,m("]"),h,e):w&&"as"==c?(d.marked="keyword",b(u,e)):void 0:void 0}function V(a,c){return"quasi"!=a?g():"${"!=c.slice(c.length-2)?b(V):b(n,Ma)}function Ma(a){if("}"==a)return d.marked="string-2",d.state.tokenize=aa,b(V)}function ra(a){return ca(d.stream,d.state),g("{"==a?t:n)}function qa(a){return ca(d.stream,d.state),g("{"==a?t:v)}function Ka(a){return function(c){return"."==
+c?b(a?Na:Oa):g(a?v:n)}}function Oa(a,c){if("target"==c)return d.marked="keyword",b(E)}function Na(a,c){if("target"==c)return d.marked="keyword",b(L)}function Da(a){return":"==a?b(h,t):g(E,m(";"),h)}function La(a){if("variable"==a)return d.marked="property",b()}function ha(a,c){return"async"==a?(d.marked="property",b(ha)):"variable"==a||"keyword"==d.style?(d.marked="property",b("get"==c||"set"==c?Pa:B)):"number"==a||"string"==a?(d.marked=T?"property":d.style+" property",b(B)):"jsonld-keyword"==a?b(B):
+"modifier"==a?b(ha):"["==a?b(n,m("]"),B):"spread"==a?b(n,B):":"==a?g(B):void 0}function Pa(a){return"variable"!=a?g(B):(d.marked="property",b(x))}function B(a){return":"==a?b(v):"("==a?g(x):void 0}function z(a,c,f){function e(A,k){if(f?-1<f.indexOf(A):","==A){var h=d.state.lexical;return"call"==h.info&&(h.pos=(h.pos||0)+1),b(function(b,e){return b==c||e==c?g():g(a)},e)}return A==c||k==c?b():b(m(c))}return function(d,f){return d==c||f==c?b():g(a,e)}}function M(a,c,f){for(var e=3;e<arguments.length;e++)d.cc.push(arguments[e]);
+return b(l(c,f),z(a,c),h)}function U(a){return"}"==a?b():g(t,U)}function N(a,c){if(w){if(":"==a)return b(u);if("?"==c)return b(N)}}function u(a){return"variable"==a?(d.marked="type",b(O)):"string"==a||"number"==a||"atom"==a?b(O):"{"==a?b(l("}"),z(W,"}",",;"),h,O):"("==a?b(z(sa,")"),Qa):void 0}function Qa(a){if("\x3d\x3e"==a)return b(u)}function W(a,c){return"variable"==a||"keyword"==d.style?(d.marked="property",b(W)):"?"==c?b(W):":"==a?b(u):"["==a?b(n,N,m("]"),W):void 0}function sa(a){return"variable"==
+a?b(sa):":"==a?b(u):void 0}function O(a,c){return"\x3c"==c?b(l("\x3e"),z(u,"\x3e"),h,O):"|"==c||"."==a?b(u):"["==a?b(m("]"),O):"extends"==c?b(u):void 0}function da(){return g(y,N,P,Ra)}function y(a,c){return"modifier"==a?b(y):"variable"==a?(I(c),b()):"spread"==a?b(y):"["==a?M(y,"]"):"{"==a?M(Sa,"}"):void 0}function Sa(a,c){return"variable"!=a||d.stream.match(/^\s*:/,!1)?("variable"==a&&(d.marked="property"),"spread"==a?b(y):"}"==a?g():b(m(":"),y,P)):(I(c),b(P))}function P(a,c){if("\x3d"==c)return b(v)}
+function Ra(a){if(","==a)return b(da)}function na(a,c){if("keyword b"==a&&"else"==c)return b(l("form","else"),t,h)}function Ca(a){if("("==a)return b(l(")"),Ta,m(")"),h)}function Ta(a){return"var"==a?b(da,m(";"),X):";"==a?b(X):"variable"==a?b(Ua):g(n,m(";"),X)}function Ua(a,c){return"in"==c||"of"==c?(d.marked="keyword",b(n)):b(E,X)}function X(a,c){return";"==a?b(ta):"in"==c||"of"==c?(d.marked="keyword",b(n)):g(n,m(";"),ta)}function ta(a){")"!=a&&b(n)}function x(a,c){return"*"==c?(d.marked="keyword",
+b(x)):"variable"==a?(I(c),b(x)):"("==a?b(J,l(")"),z(fa,")"),h,N,t,K):w&&"\x3c"==c?b(l("\x3e"),z(u,"\x3e"),h,x):void 0}function fa(a){return"spread"==a?b(fa):g(y,N,P)}function Ha(a,b){return"variable"==a?oa(a,b):Y(a,b)}function oa(a,c){if("variable"==a)return I(c),b(Y)}function Y(a,c){return"\x3c"==c?b(l("\x3e"),z(u,"\x3e"),h,Y):"extends"==c||"implements"==c||w&&","==a?b(w?u:n,Y):"{"==a?b(l("}"),C,h):void 0}function C(a,c){return"variable"==a||"keyword"==d.style?("async"==c||"static"==c||"get"==c||
+"set"==c||w&&("public"==c||"private"==c||"protected"==c||"readonly"==c||"abstract"==c))&&d.stream.match(/^\s+[\w$\xa1-\uffff]/,!1)?(d.marked="keyword",b(C)):(d.marked="property",b(w?ia:x,C)):"["==a?b(n,m("]"),w?ia:x,C):"*"==c?(d.marked="keyword",b(C)):";"==a?b(C):"}"==a?b():"@"==c?b(n,C):void 0}function ia(a,c){return"?"==c?b(ia):":"==a?b(u,P):"\x3d"==c?b(v):g(x)}function Ea(a,c){return"*"==c?(d.marked="keyword",b(ja,m(";"))):"default"==c?(d.marked="keyword",b(n,m(";"))):"{"==a?b(z(ua,"}"),ja,m(";")):
+g(t)}function ua(a,c){return"as"==c?(d.marked="keyword",b(m("variable"))):"variable"==a?g(v,ua):void 0}function Fa(a){return"string"==a?b():g(Z,va,ja)}function Z(a,c){return"{"==a?M(Z,"}"):("variable"==a&&I(c),"*"==c&&(d.marked="keyword"),b(Va))}function va(a){if(","==a)return b(Z,va)}function Va(a,c){if("as"==c)return d.marked="keyword",b(Z)}function ja(a,c){if("from"==c)return d.marked="keyword",b(n)}function Ja(a){return"]"==a?b():g(z(v,"]"))}var H,Q,F=xa.indentUnit,wa=r.statementIndent,T=r.jsonld,
+G=r.json||T,w=r.typescript,ba=r.wordCharacters||/[\w$\xa1-\uffff]/,la=function(){function a(a){return{type:a,style:"keyword"}}var b=a("keyword a"),d=a("keyword b"),e=a("keyword c"),h=a("operator"),k={type:"atom",style:"atom"},b={"if":a("if"),"while":b,"with":b,"else":d,"do":d,"try":d,"finally":d,"return":e,"break":e,"continue":e,"new":a("new"),"delete":e,"throw":e,"debugger":e,"var":a("var"),"const":a("var"),let:a("var"),"function":a("function"),"catch":a("catch"),"for":a("for"),"switch":a("switch"),
+"case":a("case"),"default":a("default"),"in":h,"typeof":h,"instanceof":h,"true":k,"false":k,"null":k,undefined:k,NaN:k,Infinity:k,"this":a("this"),"class":a("class"),"super":a("atom"),yield:e,"export":a("export"),"import":a("import"),"extends":e,await:e};if(w){var d={type:"variable",style:"type"},e={"interface":a("class"),"implements":e,namespace:e,module:a("module"),"enum":a("module"),"public":a("modifier"),"private":a("modifier"),"protected":a("modifier"),"abstract":a("modifier"),string:d,number:d,
+"boolean":d,any:d},g;for(g in e)b[g]=e[g]}return b}(),S=/[+\-*&%=<>!?|~^@]/,za=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/,Aa="([{}])",Ga={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,"this":!0,"jsonld-keyword":!0},d={state:null,column:null,marked:null,cc:null},Ba={name:"this",next:{name:"arguments"}};return h.lex=!0,{startState:function(a){a={tokenize:D,lastType:"sof",cc:[],lexical:new ma((a||0)-F,0,"block",!1),localVars:r.localVars,context:r.localVars&&
+{vars:r.localVars},indented:a||0};return r.globalVars&&"object"==typeof r.globalVars&&(a.globalVars=r.globalVars),a},token:function(a,b){if(a.sol()&&(b.lexical.hasOwnProperty("align")||(b.lexical.align=!1),b.indented=a.indentation(),ca(a,b)),b.tokenize!=R&&a.eatSpace())return null;var f=b.tokenize(a,b);if("comment"!=H){b.lastType="operator"!=H||"++"!=Q&&"--"!=Q?H:"incdec";a:{var e=H,h=Q,k=b.cc;d.state=b;d.stream=a;d.marked=null;d.cc=k;d.style=f;for(b.lexical.hasOwnProperty("align")||(b.lexical.align=
+!0);;)if((k.length?k.pop():G?n:t)(e,h)){for(;k.length&&k[k.length-1].lex;)k.pop()();if(d.marked)f=d.marked;else{if(e="variable"==e)b:{for(e=b.localVars;e;e=e.next)if(e.name==h){e=!0;break b}for(k=b.context;k;k=k.prev)for(e=k.vars;e;e=e.next)if(e.name==h){e=!0;break b}e=void 0}f=e?"variable-2":f}break a}}}return f},indent:function(a,b){if(a.tokenize==R)return p.Pass;if(a.tokenize!=D)return 0;var d,e=b&&b.charAt(0),g=a.lexical;if(!/^\s*else\b/.test(b))for(var k=a.cc.length-1;0<=k;--k){var l=a.cc[k];
+if(l==h)g=g.prev;else if(l!=na)break}for(;!("stat"!=g.type&&"form"!=g.type||"}"!=e&&(!(d=a.cc[a.cc.length-1])||d!=E&&d!=L||/^[,\.=+\-*:?[\(]/.test(b)));)g=g.prev;wa&&")"==g.type&&"stat"==g.prev.type&&(g=g.prev);d=g.type;k=e==d;"vardef"==d?e=g.indented+("operator"==a.lastType||","==a.lastType?g.info+1:0):"form"==d&&"{"==e?e=g.indented:"form"==d?e=g.indented+F:"stat"==d?(e=g.indented,g="operator"==a.lastType||","==a.lastType||S.test(b.charAt(0))||/[,.]/.test(b.charAt(0)),e+=g?wa||F:0):e="switch"!=g.info||
+k||0==r.doubleIndentSwitch?g.align?g.column+(k?0:1):g.indented+(k?0:F):g.indented+(/^(?:case|default)\b/.test(b)?F:2*F);return e},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:G?null:"/*",blockCommentEnd:G?null:"*/",lineComment:G?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:G?"json":"javascript",jsonldMode:T,jsonMode:G,expressionAllowed:ka,skipExpression:function(a){var b=a.cc[a.cc.length-1];b!=n&&b!=v||a.cc.pop()}}});p.registerHelper("wordChars","javascript",
+/[\w$]/);p.defineMIME("text/javascript","javascript");p.defineMIME("text/ecmascript","javascript");p.defineMIME("application/javascript","javascript");p.defineMIME("application/x-javascript","javascript");p.defineMIME("application/ecmascript","javascript");p.defineMIME("application/json",{name:"javascript",json:!0});p.defineMIME("application/x-json",{name:"javascript",json:!0});p.defineMIME("application/ld+json",{name:"javascript",jsonld:!0});p.defineMIME("text/typescript",{name:"javascript",typescript:!0});
+p.defineMIME("application/typescript",{name:"javascript",typescript:!0})});(function(p){"function"==typeof p.define&&p.define("modeJs",["mode/javascript/javascript.js"],function(){})})(this);
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/js/codemirror.mode.php.min.js b/js/ckeditor/plugins/codemirror/js/codemirror.mode.php.min.js
new file mode 100644 (file)
index 0000000..6005e39
--- /dev/null
@@ -0,0 +1,113 @@
+!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("mode/xml/xml",["../../lib/codemirror"],e):e(CodeMirror)}(function(e){var A={autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,
+dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0,
+caseFold:!0},C={autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1,caseFold:!1};e.defineMode("xml",function(w,x){function f(b,c){function a(g){return c.tokenize=g,g(b,c)}var g=b.next();if("\x3c"==g)return b.eat("!")?b.eat("[")?b.match("CDATA[")?a(u("atom","]]\x3e")):null:b.match("--")?a(u("comment","--\x3e")):b.match("DOCTYPE",!0,!0)?(b.eatWhile(/[\w\._\-]/),a(n(1))):null:b.eat("?")?(b.eatWhile(/[\w\._\-]/),c.tokenize=u("meta","?\x3e"),"meta"):
+(I=b.eat("/")?"closeTag":"openTag",c.tokenize=d,"tag bracket");if("\x26"==g){var e;return e=b.eat("#")?b.eat("x")?b.eatWhile(/[a-fA-F\d]/)&&b.eat(";"):b.eatWhile(/[\d]/)&&b.eat(";"):b.eatWhile(/[\w\.\-:]/)&&b.eat(";"),e?"atom":"error"}return b.eatWhile(/[^&<]/),null}function d(b,c){var a=b.next();return"\x3e"==a||"/"==a&&b.eat("\x3e")?(c.tokenize=f,I="\x3e"==a?"endTag":"selfcloseTag","tag bracket"):"\x3d"==a?(I="equals",null):"\x3c"==a?(c.tokenize=f,c.state=D,c.tagName=c.tagStart=null,(a=c.tokenize(b,
+c))?a+" tag error":"tag error"):/[\'\"]/.test(a)?(c.tokenize=t(a),c.stringStartCol=b.column(),c.tokenize(b,c)):(b.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/),"word")}function t(b){var c=function(c,a){for(;!c.eol();)if(c.next()==b){a.tokenize=d;break}return"string"};return c.isInAttribute=!0,c}function u(b,c){return function(a,g){for(;!a.eol();){if(a.match(c)){g.tokenize=f;break}a.next()}return b}}function n(b){return function(c,a){for(var g;null!=(g=c.next());){if("\x3c"==g)return a.tokenize=
+n(b+1),a.tokenize(c,a);if("\x3e"==g){if(1==b){a.tokenize=f;break}return a.tokenize=n(b-1),a.tokenize(c,a)}}return"meta"}}function y(b,c,a){this.prev=b.context;this.tagName=c;this.indent=b.indented;this.startOfLine=a;(F.doNotIndent.hasOwnProperty(c)||b.context&&b.context.noIndent)&&(this.noIndent=!0)}function m(b){b.context&&(b.context=b.context.prev)}function c(b,c){for(var a;b.context&&(a=b.context.tagName,F.contextGrabbers.hasOwnProperty(a)&&F.contextGrabbers[a].hasOwnProperty(c));)m(b)}function D(b,
+c,a){return"openTag"==b?(a.tagStart=c.column(),z):"closeTag"==b?H:D}function z(b,c,a){return"word"==b?(a.tagName=c.current(),E="tag",k):(E="error",z)}function H(b,c,a){return"word"==b?(b=c.current(),a.context&&a.context.tagName!=b&&F.implicitlyClosed.hasOwnProperty(a.context.tagName)&&m(a),a.context&&a.context.tagName==b||!1===F.matchClosing?(E="tag",v):(E="tag error",p)):(E="error",p)}function v(b,a,c){return"endTag"!=b?(E="error",v):(m(c),D)}function p(b,a,c){return E="error",v(b,a,c)}function k(b,
+g,d){if("word"==b)return E="attribute",a;if("endTag"==b||"selfcloseTag"==b){g=d.tagName;var e=d.tagStart;return d.tagName=d.tagStart=null,"selfcloseTag"==b||F.autoSelfClosers.hasOwnProperty(g)?c(d,g):(c(d,g),d.context=new y(d,g,e==d.indented)),D}return E="error",k}function a(a,c,g){return"equals"==a?b:(F.allowMissing||(E="error"),k(a,c,g))}function b(b,a,c){return"string"==b?g:"word"==b&&F.allowUnquoted?(E="string",k):(E="error",k(b,a,c))}function g(b,a,c){return"string"==b?g:k(b,a,c)}var T=w.indentUnit,
+F={},W=x.htmlMode?A:C,Q;for(Q in W)F[Q]=W[Q];for(Q in x)F[Q]=x[Q];var I,E;return f.isInText=!0,{startState:function(b){var a={tokenize:f,state:D,indented:b||0,tagName:null,tagStart:null,context:null};return null!=b&&(a.baseIndent=b),a},token:function(b,a){if(!a.tagName&&b.sol()&&(a.indented=b.indentation()),b.eatSpace())return null;I=null;var c=a.tokenize(b,a);return(c||I)&&"comment"!=c&&(E=null,a.state=a.state(I||c,b,a),E&&(c="error"==E?c+" error":E)),c},indent:function(b,a,c){var g=b.context;if(b.tokenize.isInAttribute)return b.tagStart==
+b.indented?b.stringStartCol+1:b.indented+T;if(g&&g.noIndent)return e.Pass;if(b.tokenize!=d&&b.tokenize!=f)return c?c.match(/^(\s*)/)[0].length:0;if(b.tagName)return!1!==F.multilineTagIndentPastTag?b.tagStart+b.tagName.length+2:b.tagStart+T*(F.multilineTagIndentFactor||1);if(F.alignCDATA&&/<!\[CDATA\[/.test(a))return 0;if((a=a&&/^<(\/)?([\w_:\.-]*)/.exec(a))&&a[1])for(;g;){if(g.tagName==a[2]){g=g.prev;break}if(!F.implicitlyClosed.hasOwnProperty(g.tagName))break;g=g.prev}else if(a)for(;g;){c=F.contextGrabbers[g.tagName];
+if(!c||!c.hasOwnProperty(a[2]))break;g=g.prev}for(;g&&g.prev&&!g.startOfLine;)g=g.prev;return g?g.indent+T:b.baseIndent||0},electricInput:/<\/[\s\w:]+>$/,blockCommentStart:"\x3c!--",blockCommentEnd:"--\x3e",configuration:F.htmlMode?"html":"xml",helperType:F.htmlMode?"html":"xml",skipAttribute:function(a){a.state==b&&(a.state=k)}}});e.defineMIME("text/xml","xml");e.defineMIME("application/xml","xml");e.mimeModes.hasOwnProperty("text/html")||e.defineMIME("text/html",{name:"xml",htmlMode:!0})});
+(function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("mode/javascript/javascript",["../../lib/codemirror"],e):e(CodeMirror)})(function(e){function A(e,w,x){return/^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(w.lastType)||"quasi"==w.lastType&&/\{\s*$/.test(e.string.slice(0,e.pos-(x||0)))}e.defineMode("javascript",function(C,w){function x(q,b,a){return Z=q,da=a,b}function f(q,b){var a=
+q.next();if('"'==a||"'"==a)return b.tokenize=d(a),b.tokenize(q,b);if("."==a&&q.match(/^\d+(?:[eE][+\-]?\d+)?/))return x("number","number");if("."==a&&q.match(".."))return x("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(a))return x(a);if("\x3d"==a&&q.eat("\x3e"))return x("\x3d\x3e","operator");if("0"==a&&q.eat(/x/i))return q.eatWhile(/[\da-f]/i),x("number","number");if("0"==a&&q.eat(/o/i))return q.eatWhile(/[0-7]/i),x("number","number");if("0"==a&&q.eat(/b/i))return q.eatWhile(/[01]/i),x("number",
+"number");if(/\d/.test(a))return q.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),x("number","number");if("/"==a){if(q.eat("*"))a=(b.tokenize=t,t(q,b));else if(q.eat("/"))a=(q.skipToEnd(),x("comment","comment"));else if(A(q,b,1)){a:for(var c=!1,h=!1;null!=(a=q.next());){if(!c){if("/"==a&&!h)break a;"["==a?h=!0:h&&"]"==a&&(h=!1)}c=!c&&"\\"==a}a=(q.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/),x("regexp","string-2"))}else a=(q.eatWhile(ea),x("operator","operator",q.current()));return a}if("`"==a)return b.tokenize=
+u,u(q,b);if("#"==a)return q.skipToEnd(),x("error","error");if(ea.test(a))return"\x3e"==a&&b.lexical&&"\x3e"==b.lexical.type||q.eatWhile(ea),x("operator","operator",q.current());if(la.test(a)){q.eatWhile(la);a=q.current();if("."!=b.lastType){if(ua.propertyIsEnumerable(a))return c=ua[a],x(c.type,c.style,a);if("async"==a&&q.match(/^\s*[\(\w]/,!1))return x("async","keyword",a)}return x("variable","variable",a)}}function d(q){return function(b,a){var c,h=!1;if(fa&&"@"==b.peek()&&b.match(Da))return a.tokenize=
+f,x("jsonld-keyword","meta");for(;null!=(c=b.next())&&(c!=q||h);)h=!h&&"\\"==c;return h||(a.tokenize=f),x("string","string")}}function t(q,b){for(var a,c=!1;a=q.next();){if("/"==a&&c){b.tokenize=f;break}c="*"==a}return x("comment","comment")}function u(q,b){for(var a,c=!1;null!=(a=q.next());){if(!c&&("`"==a||"$"==a&&q.eat("{"))){b.tokenize=f;break}c=!c&&"\\"==a}return x("quasi","string-2",q.current())}function n(q,a){a.fatArrowAt&&(a.fatArrowAt=null);var b=q.string.indexOf("\x3d\x3e",q.start);if(!(0>
+b)){if(K){var c=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(q.string.slice(q.start,b));c&&(b=c.index)}for(var c=0,h=!1,b=b-1;0<=b;--b){var g=q.string.charAt(b),l=Ea.indexOf(g);if(0<=l&&3>l){if(!c){++b;break}if(0==--c){"("==g&&(h=!0);break}}else if(3<=l&&6>l)++c;else if(la.test(g))h=!0;else{if(/["'\/]/.test(g))return;if(h&&!c){++b;break}}}h&&!c&&(a.fatArrowAt=b)}}function y(q,b,a,c,h,g){this.indented=q;this.column=b;this.type=a;this.prev=h;this.info=g;null!=c&&(this.align=c)}function m(){for(var q=
+arguments.length-1;0<=q;q--)r.cc.push(arguments[q])}function c(){return m.apply(null,arguments),!0}function D(q){function b(a){for(;a;a=a.next)if(a.name==q)return!0;return!1}var a=r.state;(r.marked="def",a.context)?b(a.localVars)||(a.localVars={name:q,next:a.localVars}):b(a.globalVars)||w.globalVars&&(a.globalVars={name:q,next:a.globalVars})}function z(){r.state.context={prev:r.state.context,vars:r.state.localVars};r.state.localVars=Fa}function H(){r.state.localVars=r.state.context.vars;r.state.context=
+r.state.context.prev}function v(q,a){var b=function(){var b=r.state,c=b.indented;if("stat"==b.lexical.type)c=b.lexical.indented;else for(var h=b.lexical;h&&")"==h.type&&h.align;h=h.prev)c=h.indented;b.lexical=new y(c,r.stream.column(),q,null,b.lexical,a)};return b.lex=!0,b}function p(){var b=r.state;b.lexical.prev&&(")"==b.lexical.type&&(b.indented=b.lexical.indented),b.lexical=b.lexical.prev)}function k(b){function a(h){return h==b?c():";"==b?m():c(a)}return a}function a(q,g){return"var"==q?c(v("vardef",
+g.length),B,k(";"),p):"keyword a"==q?c(v("form"),T,a,p):"keyword b"==q?c(v("form"),a,p):"{"==q?c(v("}"),R,p):";"==q?c():"if"==q?("else"==r.state.lexical.info&&r.state.cc[r.state.cc.length-1]==p&&r.state.cc.pop()(),c(v("form"),T,a,p,va)):"function"==q?c(M):"for"==q?c(v("form"),Ga,a,p):"variable"==q?K&&"type"==g?(r.marked="keyword",c(G,k("operator"),G,k(";"))):c(v("stat"),ma):"switch"==q?c(v("form"),T,k("{"),v("}","switch"),R,p,p):"case"==q?c(b,k(":")):"default"==q?c(k(":")):"catch"==q?c(v("form"),
+z,k("("),na,k(")"),a,p,H):"class"==q?c(v("form"),wa,p):"export"==q?c(v("stat"),Ha,p):"import"==q?c(v("stat"),Ia,p):"module"==q?c(v("form"),h,k("{"),v("}"),R,p,p):"async"==q?c(a):"@"==g?c(b,a):m(v("stat"),b,k(";"),p)}function b(b){return F(b,!1)}function g(b){return F(b,!0)}function T(a){return"("!=a?m():c(v(")"),b,k(")"),p)}function F(a,l){if(r.state.fatArrowAt==r.stream.start){var d=l?ta:sa;if("("==a)return c(z,v(")"),J(h,")"),p,k("\x3d\x3e"),d,H);if("variable"==a)return m(z,h,k("\x3d\x3e"),d,H)}d=
+l?E:I;return Ja.hasOwnProperty(a)?c(d):"function"==a?c(M,d):"class"==a?c(v("form"),Ka,p):"keyword c"==a||"async"==a?c(l?Q:W):"("==a?c(v(")"),W,k(")"),p,d):"operator"==a||"spread"==a?c(l?g:b):"["==a?c(v("]"),La,p,d):"{"==a?N(aa,"}",null,d):"quasi"==a?m(ba,d):"new"==a?c(Ca(l)):c()}function W(a){return a.match(/[;\}\)\],]/)?m():m(b)}function Q(a){return a.match(/[;\}\)\],]/)?m():m(g)}function I(a,h){return","==a?c(b):E(a,h,!1)}function E(a,h,l){var d=0==l?I:E,e=0==l?b:g;return"\x3d\x3e"==a?c(z,l?ta:
+sa,H):"operator"==a?/\+\+|--/.test(h)?c(d):"?"==h?c(b,k(":"),e):c(e):"quasi"==a?m(ba,d):";"!=a?"("==a?N(g,")","call",d):"."==a?c(S,d):"["==a?c(v("]"),W,k("]"),p,d):K&&"as"==h?(r.marked="keyword",c(G,d)):void 0:void 0}function ba(a,h){return"quasi"!=a?m():"${"!=h.slice(h.length-2)?c(ba):c(b,Ba)}function Ba(a){if("}"==a)return r.marked="string-2",r.state.tokenize=u,c(ba)}function sa(q){return n(r.stream,r.state),m("{"==q?a:b)}function ta(b){return n(r.stream,r.state),m("{"==b?a:g)}function Ca(a){return function(h){return"."==
+h?c(a?oa:ca):m(a?g:b)}}function ca(a,b){if("target"==b)return r.marked="keyword",c(I)}function oa(a,b){if("target"==b)return r.marked="keyword",c(E)}function ma(b){return":"==b?c(p,a):m(I,k(";"),p)}function S(a){if("variable"==a)return r.marked="property",c()}function aa(a,h){return"async"==a?(r.marked="property",c(aa)):"variable"==a||"keyword"==r.style?(r.marked="property",c("get"==h||"set"==h?pa:O)):"number"==a||"string"==a?(r.marked=fa?"property":r.style+" property",c(O)):"jsonld-keyword"==a?c(O):
+"modifier"==a?c(aa):"["==a?c(b,k("]"),O):"spread"==a?c(b,O):":"==a?m(O):void 0}function pa(a){return"variable"!=a?m(O):(r.marked="property",c(M))}function O(a){return":"==a?c(g):"("==a?m(M):void 0}function J(a,b,h){function g(l,d){if(h?-1<h.indexOf(l):","==l){var e=r.state.lexical;return"call"==e.info&&(e.pos=(e.pos||0)+1),c(function(c,h){return c==b||h==b?m():m(a)},g)}return l==b||d==b?c():c(k(b))}return function(h,l){return h==b||l==b?c():m(a,g)}}function N(a,b,h){for(var g=3;g<arguments.length;g++)r.cc.push(arguments[g]);
+return c(v(b,h),J(a,b),p)}function R(b){return"}"==b?c():m(a,R)}function P(a,b){if(K){if(":"==a)return c(G);if("?"==b)return c(P)}}function G(a){return"variable"==a?(r.marked="type",c(U)):"string"==a||"number"==a||"atom"==a?c(U):"{"==a?c(v("}"),J(L,"}",",;"),p,U):"("==a?c(J(ga,")"),ha):void 0}function ha(a){if("\x3d\x3e"==a)return c(G)}function L(a,h){return"variable"==a||"keyword"==r.style?(r.marked="property",c(L)):"?"==h?c(L):":"==a?c(G):"["==a?c(b,P,k("]"),L):void 0}function ga(a){return"variable"==
+a?c(ga):":"==a?c(G):void 0}function U(a,b){return"\x3c"==b?c(v("\x3e"),J(G,"\x3e"),p,U):"|"==b||"."==a?c(G):"["==a?c(k("]"),U):"extends"==b?c(G):void 0}function B(){return m(h,P,l,Ma)}function h(a,b){return"modifier"==a?c(h):"variable"==a?(D(b),c()):"spread"==a?c(h):"["==a?N(h,"]"):"{"==a?N(Na,"}"):void 0}function Na(a,b){return"variable"!=a||r.stream.match(/^\s*:/,!1)?("variable"==a&&(r.marked="property"),"spread"==a?c(h):"}"==a?m():c(k(":"),h,l)):(D(b),c(l))}function l(a,b){if("\x3d"==b)return c(g)}
+function Ma(a){if(","==a)return c(B)}function va(b,h){if("keyword b"==b&&"else"==h)return c(v("form","else"),a,p)}function Ga(a){if("("==a)return c(v(")"),Oa,k(")"),p)}function Oa(a){return"var"==a?c(B,k(";"),ia):";"==a?c(ia):"variable"==a?c(Pa):m(b,k(";"),ia)}function Pa(a,h){return"in"==h||"of"==h?(r.marked="keyword",c(b)):c(I,ia)}function ia(a,h){return";"==a?c(xa):"in"==h||"of"==h?(r.marked="keyword",c(b)):m(b,k(";"),xa)}function xa(a){")"!=a&&c(b)}function M(b,h){return"*"==h?(r.marked="keyword",
+c(M)):"variable"==b?(D(h),c(M)):"("==b?c(z,v(")"),J(na,")"),p,P,a,H):K&&"\x3c"==h?c(v("\x3e"),J(G,"\x3e"),p,M):void 0}function na(a){return"spread"==a?c(na):m(h,P,l)}function Ka(a,b){return"variable"==a?wa(a,b):ja(a,b)}function wa(a,b){if("variable"==a)return D(b),c(ja)}function ja(a,h){return"\x3c"==h?c(v("\x3e"),J(G,"\x3e"),p,ja):"extends"==h||"implements"==h||K&&","==a?c(K?G:b,ja):"{"==a?c(v("}"),V,p):void 0}function V(a,h){return"variable"==a||"keyword"==r.style?("async"==h||"static"==h||"get"==
+h||"set"==h||K&&("public"==h||"private"==h||"protected"==h||"readonly"==h||"abstract"==h))&&r.stream.match(/^\s+[\w$\xa1-\uffff]/,!1)?(r.marked="keyword",c(V)):(r.marked="property",c(K?qa:M,V)):"["==a?c(b,k("]"),K?qa:M,V):"*"==h?(r.marked="keyword",c(V)):";"==a?c(V):"}"==a?c():"@"==h?c(b,V):void 0}function qa(a,b){return"?"==b?c(qa):":"==a?c(G,l):"\x3d"==b?c(g):m(M)}function Ha(h,g){return"*"==g?(r.marked="keyword",c(ra,k(";"))):"default"==g?(r.marked="keyword",c(b,k(";"))):"{"==h?c(J(ya,"}"),ra,
+k(";")):m(a)}function ya(a,b){return"as"==b?(r.marked="keyword",c(k("variable"))):"variable"==a?m(g,ya):void 0}function Ia(a){return"string"==a?c():m(ka,za,ra)}function ka(a,b){return"{"==a?N(ka,"}"):("variable"==a&&D(b),"*"==b&&(r.marked="keyword"),c(Qa))}function za(a){if(","==a)return c(ka,za)}function Qa(a,b){if("as"==b)return r.marked="keyword",c(ka)}function ra(a,h){if("from"==h)return r.marked="keyword",c(b)}function La(a){return"]"==a?c():m(J(g,"]"))}var Z,da,X=C.indentUnit,Aa=w.statementIndent,
+fa=w.jsonld,Y=w.json||fa,K=w.typescript,la=w.wordCharacters||/[\w$\xa1-\uffff]/,ua=function(){function a(b){return{type:b,style:"keyword"}}var b=a("keyword a"),h=a("keyword b"),c=a("keyword c"),g=a("operator"),l={type:"atom",style:"atom"},b={"if":a("if"),"while":b,"with":b,"else":h,"do":h,"try":h,"finally":h,"return":c,"break":c,"continue":c,"new":a("new"),"delete":c,"throw":c,"debugger":c,"var":a("var"),"const":a("var"),let:a("var"),"function":a("function"),"catch":a("catch"),"for":a("for"),"switch":a("switch"),
+"case":a("case"),"default":a("default"),"in":g,"typeof":g,"instanceof":g,"true":l,"false":l,"null":l,undefined:l,NaN:l,Infinity:l,"this":a("this"),"class":a("class"),"super":a("atom"),yield:c,"export":a("export"),"import":a("import"),"extends":c,await:c};if(K){var h={type:"variable",style:"type"},c={"interface":a("class"),"implements":c,namespace:c,module:a("module"),"enum":a("module"),"public":a("modifier"),"private":a("modifier"),"protected":a("modifier"),"abstract":a("modifier"),string:h,number:h,
+"boolean":h,any:h},d;for(d in c)b[d]=c[d]}return b}(),ea=/[+\-*&%=<>!?|~^@]/,Da=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/,Ea="([{}])",Ja={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,"this":!0,"jsonld-keyword":!0},r={state:null,column:null,marked:null,cc:null},Fa={name:"this",next:{name:"arguments"}};return p.lex=!0,{startState:function(a){a={tokenize:f,lastType:"sof",cc:[],lexical:new y((a||0)-X,0,"block",!1),localVars:w.localVars,context:w.localVars&&
+{vars:w.localVars},indented:a||0};return w.globalVars&&"object"==typeof w.globalVars&&(a.globalVars=w.globalVars),a},token:function(h,c){if(h.sol()&&(c.lexical.hasOwnProperty("align")||(c.lexical.align=!1),c.indented=h.indentation(),n(h,c)),c.tokenize!=t&&h.eatSpace())return null;var g=c.tokenize(h,c);if("comment"!=Z){c.lastType="operator"!=Z||"++"!=da&&"--"!=da?Z:"incdec";a:{var l=Z,d=da,e=c.cc;r.state=c;r.stream=h;r.marked=null;r.cc=e;r.style=g;for(c.lexical.hasOwnProperty("align")||(c.lexical.align=
+!0);;)if((e.length?e.pop():Y?b:a)(l,d)){for(;e.length&&e[e.length-1].lex;)e.pop()();if(r.marked)g=r.marked;else{if(l="variable"==l)b:{for(l=c.localVars;l;l=l.next)if(l.name==d){l=!0;break b}for(e=c.context;e;e=e.prev)for(l=e.vars;l;l=l.next)if(l.name==d){l=!0;break b}l=void 0}g=l?"variable-2":g}break a}}}return g},indent:function(a,b){if(a.tokenize==t)return e.Pass;if(a.tokenize!=f)return 0;var h,c=b&&b.charAt(0),l=a.lexical;if(!/^\s*else\b/.test(b))for(var g=a.cc.length-1;0<=g;--g){var d=a.cc[g];
+if(d==p)l=l.prev;else if(d!=va)break}for(;!("stat"!=l.type&&"form"!=l.type||"}"!=c&&(!(h=a.cc[a.cc.length-1])||h!=I&&h!=E||/^[,\.=+\-*:?[\(]/.test(b)));)l=l.prev;Aa&&")"==l.type&&"stat"==l.prev.type&&(l=l.prev);h=l.type;g=c==h;"vardef"==h?c=l.indented+("operator"==a.lastType||","==a.lastType?l.info+1:0):"form"==h&&"{"==c?c=l.indented:"form"==h?c=l.indented+X:"stat"==h?(c=l.indented,l="operator"==a.lastType||","==a.lastType||ea.test(b.charAt(0))||/[,.]/.test(b.charAt(0)),c+=l?Aa||X:0):c="switch"!=
+l.info||g||0==w.doubleIndentSwitch?l.align?l.column+(g?0:1):l.indented+(g?0:X):l.indented+(/^(?:case|default)\b/.test(b)?X:2*X);return c},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:Y?null:"/*",blockCommentEnd:Y?null:"*/",lineComment:Y?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:Y?"json":"javascript",jsonldMode:fa,jsonMode:Y,expressionAllowed:A,skipExpression:function(a){var h=a.cc[a.cc.length-1];h!=b&&h!=g||a.cc.pop()}}});e.registerHelper("wordChars",
+"javascript",/[\w$]/);e.defineMIME("text/javascript","javascript");e.defineMIME("text/ecmascript","javascript");e.defineMIME("application/javascript","javascript");e.defineMIME("application/x-javascript","javascript");e.defineMIME("application/ecmascript","javascript");e.defineMIME("application/json",{name:"javascript",json:!0});e.defineMIME("application/x-json",{name:"javascript",json:!0});e.defineMIME("application/ld+json",{name:"javascript",jsonld:!0});e.defineMIME("text/typescript",{name:"javascript",
+typescript:!0});e.defineMIME("application/typescript",{name:"javascript",typescript:!0})});
+(function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("mode/css/css",["../../lib/codemirror"],e):e(CodeMirror)})(function(e){function A(a){for(var b={},c=0;c<a.length;++c)b[a[c].toLowerCase()]=!0;return b}function C(a,b){for(var c,d=!1;null!=(c=a.next());){if(d&&"/"==c){b.tokenize=null;break}d="*"==c}return["comment","comment"]}e.defineMode("css",function(a,b){function c(a,b){var l=a.next();if(v[l]){var g=v[l](a,
+b);if(!1!==g)return g}"@"==l?(a.eatWhile(/[\w\\\-]/),l=(p=a.current(),"def")):l="\x3d"==l||("~"==l||"|"==l)&&a.eat("\x3d")?(p="compare",null):'"'==l||"'"==l?(b.tokenize=d(l),b.tokenize(a,b)):"#"==l?(a.eatWhile(/[\w\\\-]/),p="hash","atom"):"!"==l?(a.match(/^\s*\w*/),p="important","keyword"):/\d/.test(l)||"."==l&&a.eat(/\d/)?(a.eatWhile(/[\w.%]/),p="unit","number"):"-"!==l?/[,+>*\/]/.test(l)?(p="select-op",null):"."==l&&a.match(/^-?[_a-z][_a-z0-9-]*/i)?(p="qualifier","qualifier"):/[:;{}\[\]\(\)]/.test(l)?
+(p=l,null):"u"==l&&a.match(/rl(-prefix)?\(/)||"d"==l&&a.match("omain(")||"r"==l&&a.match("egexp(")?(a.backUp(1),b.tokenize=y,p="word","property"):/[\w\\\-]/.test(l)?(a.eatWhile(/[\w\\\-]/),p="word","property"):(p=null,null):/[\d.]/.test(a.peek())?(a.eatWhile(/[\w.%]/),p="unit","number"):a.match(/^-[\w\\\-]+/)?(a.eatWhile(/[\w\\\-]/),a.match(/^\s*:/,!1)?(p="variable-definition","variable-2"):(p="variable","variable-2")):a.match(/^\w+-/)?(p="meta","meta"):void 0;return l}function d(a){return function(b,
+c){for(var g,d=!1;null!=(g=b.next());){if(g==a&&!d){")"==a&&b.backUp(1);break}d=!d&&"\\"==g}return(g==a||!d&&")"!=a)&&(c.tokenize=null),p="string","string"}}function y(a,b){return a.next(),a.match(/\s*[\"\')]/,!1)?b.tokenize=null:b.tokenize=d(")"),p="(",null}function m(a,b,c){this.type=a;this.indent=b;this.prev=c}function n(a,b,c,g){return a.context=new m(c,b.indentation()+(!1===g?0:D),a.context),c}function t(a){return a.context.prev&&(a.context=a.context.prev),a.context.type}function f(a,b,c,g){for(g=
+g||1;0<g;g--)c.context=c.context.prev;return B[c.context.type](a,b,c)}function u(a){a=a.current().toLowerCase();k=ha.hasOwnProperty(a)?"atom":G.hasOwnProperty(a)?"keyword":"variable"}var z=b.inline;b.propertyKeywords||(b=e.resolveMode("text/css"));var p,k,D=a.indentUnit,v=b.tokenHooks,w=b.documentTypes||{},x=b.mediaTypes||{},A=b.mediaFeatures||{},H=b.mediaValueKeywords||{},C=b.propertyKeywords||{},N=b.nonStandardPropertyKeywords||{},R=b.fontProperties||{},P=b.counterDescriptors||{},G=b.colorKeywords||
+{},ha=b.valueKeywords||{},L=b.allowNested,ga=b.lineComment,U=!0===b.supportsAtComponent,B={};return B.top=function(a,b,c){if("{"==a)return n(c,b,"block");if("}"==a&&c.context.prev)return t(c);if(U&&/@component/.test(a))return n(c,b,"atComponentBlock");if(/^@(-moz-)?document$/.test(a))return n(c,b,"documentTypes");if(/^@(media|supports|(-moz-)?document|import)$/.test(a))return n(c,b,"atBlock");if(/^@(font-face|counter-style)/.test(a))return c.stateArg=a,"restricted_atBlock_before";if(/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(a))return"keyframes";
+if(a&&"@"==a.charAt(0))return n(c,b,"at");if("hash"==a)k="builtin";else if("word"==a)k="tag";else{if("variable-definition"==a)return"maybeprop";if("interpolation"==a)return n(c,b,"interpolation");if(":"==a)return"pseudo";if(L&&"("==a)return n(c,b,"parens")}return c.context.type},B.block=function(a,b,c){return"word"==a?(a=b.current().toLowerCase(),C.hasOwnProperty(a)?(k="property","maybeprop"):N.hasOwnProperty(a)?(k="string-2","maybeprop"):L?(k=b.match(/^\s*:(?:\s|$)/,!1)?"property":"tag","block"):
+(k+=" error","maybeprop")):"meta"==a?"block":L||"hash"!=a&&"qualifier"!=a?B.top(a,b,c):(k="error","block")},B.maybeprop=function(a,b,c){return":"==a?n(c,b,"prop"):B[c.context.type](a,b,c)},B.prop=function(a,b,c){if(";"==a)return t(c);if("{"==a&&L)return n(c,b,"propBlock");if("}"==a||"{"==a)return f(a,b,c);if("("==a)return n(c,b,"parens");if("hash"!=a||/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(b.current()))if("word"==a)u(b);else{if("interpolation"==a)return n(c,b,"interpolation")}else k+=
+" error";return"prop"},B.propBlock=function(a,b,c){return"}"==a?t(c):"word"==a?(k="property","maybeprop"):c.context.type},B.parens=function(a,b,c){return"{"==a||"}"==a?f(a,b,c):")"==a?t(c):"("==a?n(c,b,"parens"):"interpolation"==a?n(c,b,"interpolation"):("word"==a&&u(b),"parens")},B.pseudo=function(a,b,c){return"meta"==a?"pseudo":"word"==a?(k="variable-3",c.context.type):B[c.context.type](a,b,c)},B.documentTypes=function(a,b,c){return"word"==a&&w.hasOwnProperty(b.current())?(k="tag",c.context.type):
+B.atBlock(a,b,c)},B.atBlock=function(a,b,c){if("("==a)return n(c,b,"atBlock_parens");if("}"==a||";"==a)return f(a,b,c);if("{"==a)return t(c)&&n(c,b,L?"block":"top");if("interpolation"==a)return n(c,b,"interpolation");"word"==a&&(a=b.current().toLowerCase(),k="only"==a||"not"==a||"and"==a||"or"==a?"keyword":x.hasOwnProperty(a)?"attribute":A.hasOwnProperty(a)?"property":H.hasOwnProperty(a)?"keyword":C.hasOwnProperty(a)?"property":N.hasOwnProperty(a)?"string-2":ha.hasOwnProperty(a)?"atom":G.hasOwnProperty(a)?
+"keyword":"error");return c.context.type},B.atComponentBlock=function(a,b,c){return"}"==a?f(a,b,c):"{"==a?t(c)&&n(c,b,L?"block":"top",!1):("word"==a&&(k="error"),c.context.type)},B.atBlock_parens=function(a,b,c){return")"==a?t(c):"{"==a||"}"==a?f(a,b,c,2):B.atBlock(a,b,c)},B.restricted_atBlock_before=function(a,b,c){return"{"==a?n(c,b,"restricted_atBlock"):"word"==a&&"@counter-style"==c.stateArg?(k="variable","restricted_atBlock_before"):B[c.context.type](a,b,c)},B.restricted_atBlock=function(a,b,
+c){return"}"==a?(c.stateArg=null,t(c)):"word"==a?(k="@font-face"==c.stateArg&&!R.hasOwnProperty(b.current().toLowerCase())||"@counter-style"==c.stateArg&&!P.hasOwnProperty(b.current().toLowerCase())?"error":"property","maybeprop"):"restricted_atBlock"},B.keyframes=function(a,b,c){return"word"==a?(k="variable","keyframes"):"{"==a?n(c,b,"top"):B[c.context.type](a,b,c)},B.at=function(a,b,c){return";"==a?t(c):"{"==a||"}"==a?f(a,b,c):("word"==a?k="tag":"hash"==a&&(k="builtin"),"at")},B.interpolation=function(a,
+b,c){return"}"==a?t(c):"{"==a||";"==a?f(a,b,c):("word"==a?k="variable":"variable"!=a&&"("!=a&&")"!=a&&(k="error"),"interpolation")},{startState:function(a){return{tokenize:null,state:z?"block":"top",stateArg:null,context:new m(z?"block":"top",a||0,null)}},token:function(a,b){if(!b.tokenize&&a.eatSpace())return null;var g=(b.tokenize||c)(a,b);return g&&"object"==typeof g&&(p=g[1],g=g[0]),k=g,b.state=B[b.state](p,a,b),k},indent:function(a,b){var c=a.context,g=b&&b.charAt(0),d=c.indent;return"prop"!=
+c.type||"}"!=g&&")"!=g||(c=c.prev),c.prev&&("}"!=g||"block"!=c.type&&"top"!=c.type&&"interpolation"!=c.type&&"restricted_atBlock"!=c.type?(")"!=g||"parens"!=c.type&&"atBlock_parens"!=c.type)&&("{"!=g||"at"!=c.type&&"atBlock"!=c.type)||(d=Math.max(0,c.indent-D)):(c=c.prev,d=c.indent)),d},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",lineComment:ga,fold:"brace"}});var w=["domain","regexp","url","url-prefix"],x=A(w),f="all aural braille handheld print projection screen tty tv embossed".split(" "),
+d=A(f),t="width min-width max-width height min-height max-height device-width min-device-width max-device-width device-height min-device-height max-device-height aspect-ratio min-aspect-ratio max-aspect-ratio device-aspect-ratio min-device-aspect-ratio max-device-aspect-ratio color min-color max-color color-index min-color-index max-color-index monochrome min-monochrome max-monochrome resolution min-resolution max-resolution scan grid orientation device-pixel-ratio min-device-pixel-ratio max-device-pixel-ratio pointer any-pointer hover any-hover".split(" "),
+u=A(t),n="landscape portrait none coarse fine on-demand hover interlace progressive".split(" "),y=A(n),m="align-content align-items align-self alignment-adjust alignment-baseline anchor-point animation animation-delay animation-direction animation-duration animation-fill-mode animation-iteration-count animation-name animation-play-state animation-timing-function appearance azimuth backface-visibility background background-attachment background-blend-mode background-clip background-color background-image background-origin background-position background-repeat background-size baseline-shift binding bleed bookmark-label bookmark-level bookmark-state bookmark-target border border-bottom border-bottom-color border-bottom-left-radius border-bottom-right-radius border-bottom-style border-bottom-width border-collapse border-color border-image border-image-outset border-image-repeat border-image-slice border-image-source border-image-width border-left border-left-color border-left-style border-left-width border-radius border-right border-right-color border-right-style border-right-width border-spacing border-style border-top border-top-color border-top-left-radius border-top-right-radius border-top-style border-top-width border-width bottom box-decoration-break box-shadow box-sizing break-after break-before break-inside caption-side caret-color clear clip color color-profile column-count column-fill column-gap column-rule column-rule-color column-rule-style column-rule-width column-span column-width columns content counter-increment counter-reset crop cue cue-after cue-before cursor direction display dominant-baseline drop-initial-after-adjust drop-initial-after-align drop-initial-before-adjust drop-initial-before-align drop-initial-size drop-initial-value elevation empty-cells fit fit-position flex flex-basis flex-direction flex-flow flex-grow flex-shrink flex-wrap float float-offset flow-from flow-into font font-feature-settings font-family font-kerning font-language-override font-size font-size-adjust font-stretch font-style font-synthesis font-variant font-variant-alternates font-variant-caps font-variant-east-asian font-variant-ligatures font-variant-numeric font-variant-position font-weight grid grid-area grid-auto-columns grid-auto-flow grid-auto-rows grid-column grid-column-end grid-column-gap grid-column-start grid-gap grid-row grid-row-end grid-row-gap grid-row-start grid-template grid-template-areas grid-template-columns grid-template-rows hanging-punctuation height hyphens icon image-orientation image-rendering image-resolution inline-box-align justify-content justify-items justify-self left letter-spacing line-break line-height line-stacking line-stacking-ruby line-stacking-shift line-stacking-strategy list-style list-style-image list-style-position list-style-type margin margin-bottom margin-left margin-right margin-top marks marquee-direction marquee-loop marquee-play-count marquee-speed marquee-style max-height max-width min-height min-width move-to nav-down nav-index nav-left nav-right nav-up object-fit object-position opacity order orphans outline outline-color outline-offset outline-style outline-width overflow overflow-style overflow-wrap overflow-x overflow-y padding padding-bottom padding-left padding-right padding-top page page-break-after page-break-before page-break-inside page-policy pause pause-after pause-before perspective perspective-origin pitch pitch-range place-content place-items place-self play-during position presentation-level punctuation-trim quotes region-break-after region-break-before region-break-inside region-fragment rendering-intent resize rest rest-after rest-before richness right rotation rotation-point ruby-align ruby-overhang ruby-position ruby-span shape-image-threshold shape-inside shape-margin shape-outside size speak speak-as speak-header speak-numeral speak-punctuation speech-rate stress string-set tab-size table-layout target target-name target-new target-position text-align text-align-last text-decoration text-decoration-color text-decoration-line text-decoration-skip text-decoration-style text-emphasis text-emphasis-color text-emphasis-position text-emphasis-style text-height text-indent text-justify text-outline text-overflow text-shadow text-size-adjust text-space-collapse text-transform text-underline-position text-wrap top transform transform-origin transform-style transition transition-delay transition-duration transition-property transition-timing-function unicode-bidi user-select vertical-align visibility voice-balance voice-duration voice-family voice-pitch voice-range voice-rate voice-stress voice-volume volume white-space widows width will-change word-break word-spacing word-wrap z-index clip-path clip-rule mask enable-background filter flood-color flood-opacity lighting-color stop-color stop-opacity pointer-events color-interpolation color-interpolation-filters color-rendering fill fill-opacity fill-rule image-rendering marker marker-end marker-mid marker-start shape-rendering stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-rendering baseline-shift dominant-baseline glyph-orientation-horizontal glyph-orientation-vertical text-anchor writing-mode".split(" "),
+c=A(m),D="scrollbar-arrow-color scrollbar-base-color scrollbar-dark-shadow-color scrollbar-face-color scrollbar-highlight-color scrollbar-shadow-color scrollbar-3d-light-color scrollbar-track-color shape-inside searchfield-cancel-button searchfield-decoration searchfield-results-button searchfield-results-decoration zoom".split(" "),z=A(D),H=A("font-family src unicode-range font-variant font-feature-settings font-stretch font-weight font-style".split(" ")),v=A("additive-symbols fallback negative pad prefix range speak-as suffix symbols system".split(" ")),
+p="aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkturquoise darkviolet deeppink deepskyblue dimgray dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray grey green greenyellow honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightpink lightsalmon lightseagreen lightskyblue lightslategray lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray snow springgreen steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen".split(" "),
+k=A(p),a="above absolute activeborder additive activecaption afar after-white-space ahead alias all all-scroll alphabetic alternate always amharic amharic-abegede antialiased appworkspace arabic-indic armenian asterisks attr auto auto-flow avoid avoid-column avoid-page avoid-region background backwards baseline below bidi-override binary bengali blink block block-axis bold bolder border border-box both bottom break break-all break-word bullets button button-bevel buttonface buttonhighlight buttonshadow buttontext calc cambodian capitalize caps-lock-indicator caption captiontext caret cell center checkbox circle cjk-decimal cjk-earthly-branch cjk-heavenly-stem cjk-ideographic clear clip close-quote col-resize collapse color color-burn color-dodge column column-reverse compact condensed contain content contents content-box context-menu continuous copy counter counters cover crop cross crosshair currentcolor cursive cyclic darken dashed decimal decimal-leading-zero default default-button dense destination-atop destination-in destination-out destination-over devanagari difference disc discard disclosure-closed disclosure-open document dot-dash dot-dot-dash dotted double down e-resize ease ease-in ease-in-out ease-out element ellipse ellipsis embed end ethiopic ethiopic-abegede ethiopic-abegede-am-et ethiopic-abegede-gez ethiopic-abegede-ti-er ethiopic-abegede-ti-et ethiopic-halehame-aa-er ethiopic-halehame-aa-et ethiopic-halehame-am-et ethiopic-halehame-gez ethiopic-halehame-om-et ethiopic-halehame-sid-et ethiopic-halehame-so-et ethiopic-halehame-ti-er ethiopic-halehame-ti-et ethiopic-halehame-tig ethiopic-numeric ew-resize exclusion expanded extends extra-condensed extra-expanded fantasy fast fill fixed flat flex flex-end flex-start footnotes forwards from geometricPrecision georgian graytext grid groove gujarati gurmukhi hand hangul hangul-consonant hard-light hebrew help hidden hide higher highlight highlighttext hiragana hiragana-iroha horizontal hsl hsla hue icon ignore inactiveborder inactivecaption inactivecaptiontext infinite infobackground infotext inherit initial inline inline-axis inline-block inline-flex inline-grid inline-table inset inside intrinsic invert italic japanese-formal japanese-informal justify kannada katakana katakana-iroha keep-all khmer korean-hangul-formal korean-hanja-formal korean-hanja-informal landscape lao large larger left level lighter lighten line-through linear linear-gradient lines list-item listbox listitem local logical loud lower lower-alpha lower-armenian lower-greek lower-hexadecimal lower-latin lower-norwegian lower-roman lowercase ltr luminosity malayalam match matrix matrix3d media-controls-background media-current-time-display media-fullscreen-button media-mute-button media-play-button media-return-to-realtime-button media-rewind-button media-seek-back-button media-seek-forward-button media-slider media-sliderthumb media-time-remaining-display media-volume-slider media-volume-slider-container media-volume-sliderthumb medium menu menulist menulist-button menulist-text menulist-textfield menutext message-box middle min-intrinsic mix mongolian monospace move multiple multiply myanmar n-resize narrower ne-resize nesw-resize no-close-quote no-drop no-open-quote no-repeat none normal not-allowed nowrap ns-resize numbers numeric nw-resize nwse-resize oblique octal opacity open-quote optimizeLegibility optimizeSpeed oriya oromo outset outside outside-shape overlay overline padding padding-box painted page paused persian perspective plus-darker plus-lighter pointer polygon portrait pre pre-line pre-wrap preserve-3d progress push-button radial-gradient radio read-only read-write read-write-plaintext-only rectangle region relative repeat repeating-linear-gradient repeating-radial-gradient repeat-x repeat-y reset reverse rgb rgba ridge right rotate rotate3d rotateX rotateY rotateZ round row row-resize row-reverse rtl run-in running s-resize sans-serif saturation scale scale3d scaleX scaleY scaleZ screen scroll scrollbar scroll-position se-resize searchfield searchfield-cancel-button searchfield-decoration searchfield-results-button searchfield-results-decoration self-start self-end semi-condensed semi-expanded separate serif show sidama simp-chinese-formal simp-chinese-informal single skew skewX skewY skip-white-space slide slider-horizontal slider-vertical sliderthumb-horizontal sliderthumb-vertical slow small small-caps small-caption smaller soft-light solid somali source-atop source-in source-out source-over space space-around space-between space-evenly spell-out square square-button start static status-bar stretch stroke sub subpixel-antialiased super sw-resize symbolic symbols system-ui table table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group tamil telugu text text-bottom text-top textarea textfield thai thick thin threeddarkshadow threedface threedhighlight threedlightshadow threedshadow tibetan tigre tigrinya-er tigrinya-er-abegede tigrinya-et tigrinya-et-abegede to top trad-chinese-formal trad-chinese-informal transform translate translate3d translateX translateY translateZ transparent ultra-condensed ultra-expanded underline unset up upper-alpha upper-armenian upper-greek upper-hexadecimal upper-latin upper-norwegian upper-roman uppercase urdu url var vertical vertical-text visible visibleFill visiblePainted visibleStroke visual w-resize wait wave wider window windowframe windowtext words wrap wrap-reverse x-large x-small xor xx-large xx-small".split(" "),
+b=A(a),w=w.concat(f).concat(t).concat(n).concat(m).concat(D).concat(p).concat(a);e.registerHelper("hintWords","css",w);e.defineMIME("text/css",{documentTypes:x,mediaTypes:d,mediaFeatures:u,mediaValueKeywords:y,propertyKeywords:c,nonStandardPropertyKeywords:z,fontProperties:H,counterDescriptors:v,colorKeywords:k,valueKeywords:b,tokenHooks:{"/":function(a,b){return!!a.eat("*")&&(b.tokenize=C,C(a,b))}},name:"css"});e.defineMIME("text/x-scss",{mediaTypes:d,mediaFeatures:u,mediaValueKeywords:y,propertyKeywords:c,
+nonStandardPropertyKeywords:z,colorKeywords:k,valueKeywords:b,fontProperties:H,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(a,b){return a.eat("/")?(a.skipToEnd(),["comment","comment"]):a.eat("*")?(b.tokenize=C,C(a,b)):["operator","operator"]},":":function(a){return!!a.match(/\s*\{/,!1)&&[null,null]},$:function(a){return a.match(/^[\w-]+/),a.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"#":function(a){return!!a.eat("{")&&[null,"interpolation"]}},name:"css",
+helperType:"scss"});e.defineMIME("text/x-less",{mediaTypes:d,mediaFeatures:u,mediaValueKeywords:y,propertyKeywords:c,nonStandardPropertyKeywords:z,colorKeywords:k,valueKeywords:b,fontProperties:H,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(a,b){return a.eat("/")?(a.skipToEnd(),["comment","comment"]):a.eat("*")?(b.tokenize=C,C(a,b)):["operator","operator"]},"@":function(a){return a.eat("{")?[null,"interpolation"]:!a.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/,
+!1)&&(a.eatWhile(/[\w\\\-]/),a.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"])},"\x26":function(){return["atom","atom"]}},name:"css",helperType:"less"});e.defineMIME("text/x-gss",{documentTypes:x,mediaTypes:d,mediaFeatures:u,propertyKeywords:c,nonStandardPropertyKeywords:z,fontProperties:H,counterDescriptors:v,colorKeywords:k,valueKeywords:b,supportsAtComponent:!0,tokenHooks:{"/":function(a,b){return!!a.eat("*")&&(b.tokenize=C,C(a,b))}},name:"css",helperType:"gss"})});
+(function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("../xml/xml"),require("../javascript/javascript"),require("../css/css")):"function"==typeof define&&define.amd?define("mode/htmlmixed/htmlmixed",["../../lib/codemirror","../xml/xml","../javascript/javascript","../css/css"],e):e(CodeMirror)})(function(e){function A(d,e){var u=d.match(f[e]||(f[e]=new RegExp("\\s+"+e+"\\s*\x3d\\s*('|\")?([^'\"]+)('|\")?\\s*")));return u?/^\s*(.*?)\s*$/.exec(u[2])[1]:
+""}function C(d,e){for(var f in d)for(var n=e[f]||(e[f]=[]),y=d[f],m=y.length-1;0<=m;m--)n.unshift(y[m])}function w(d,e){for(var f=0;f<d.length;f++){var n=d[f];if(!n[0]||n[1].test(A(e,n[0])))return n[2]}}var x={script:[["lang",/(javascript|babel)/i,"javascript"],["type",/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i,"javascript"],["type",/./,"text/plain"],[null,null,"javascript"]],style:[["lang",/^css$/i,"css"],["type",/^(text\/)?(x-)?(stylesheet|css)$/i,"css"],["type",/./,"text/plain"],
+[null,null,"css"]]},f={};e.defineMode("htmlmixed",function(d,f){function u(c,f){var m,t=n.token(c,f.htmlState),p=/\btag\b/.test(t);if(p&&!/[<>\s\/]/.test(c.current())&&(m=f.htmlState.tagName&&f.htmlState.tagName.toLowerCase())&&y.hasOwnProperty(m))f.inTag=m+" ";else if(f.inTag&&p&&/>$/.test(c.current())){m=/^([\S]+) (.*)/.exec(f.inTag);f.inTag=null;var p="\x3e"==c.current()&&w(y[m[1]],m[2]),p=e.getMode(d,p),k=new RegExp("^\x3c/s*"+m[1]+"s*\x3e","i"),a=new RegExp("\x3c/s*"+m[1]+"s*\x3e","i");f.token=
+function(b,c){var d;if(b.match(k,!1))d=(c.token=u,c.localState=c.localMode=null,null);else{d=c.localMode.token(b,c.localState);var e=b.current(),f=e.search(a);d=(-1<f?b.backUp(e.length-f):e.match(/<\/?$/)&&(b.backUp(e.length),b.match(a,!1)||b.match(e)),d)}return d};f.localMode=p;f.localState=e.startState(p,n.indent(f.htmlState,""))}else f.inTag&&(f.inTag+=c.current(),c.eol()&&(f.inTag+=" "));return t}var n=e.getMode(d,{name:"xml",htmlMode:!0,multilineTagIndentFactor:f.multilineTagIndentFactor,multilineTagIndentPastTag:f.multilineTagIndentPastTag}),
+y={},m=f&&f.tags,c=f&&f.scriptTypes;if(C(x,y),m&&C(m,y),c)for(m=c.length-1;0<=m;m--)y.script.unshift(["type",c[m].matches,c[m].mode]);return{startState:function(){return{token:u,inTag:null,localMode:null,localState:null,htmlState:e.startState(n)}},copyState:function(c){var d;return c.localState&&(d=e.copyState(c.localMode,c.localState)),{token:c.token,inTag:c.inTag,localMode:c.localMode,localState:d,htmlState:e.copyState(n,c.htmlState)}},token:function(c,d){return d.token(c,d)},indent:function(c,
+d,f){return!c.localMode||/^\s*<\//.test(d)?n.indent(c.htmlState,d):c.localMode.indent?c.localMode.indent(c.localState,d,f):e.Pass},innerMode:function(c){return{state:c.localState||c.htmlState,mode:c.localMode||n}}}},"xml","javascript","css");e.defineMIME("text/html","htmlmixed")});
+(function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("mode/clike/clike",["../../lib/codemirror"],e):e(CodeMirror)})(function(e){function A(a,b,c,d,e,f){this.indented=a;this.column=b;this.type=c;this.info=d;this.align=e;this.prev=f}function C(a,b,c,d){var e=a.indented;return a.context&&"statement"==a.context.type&&"statement"!=c&&(e=a.context.indented),a.context=new A(e,b,c,d,null,a.context)}function w(a){var b=
+a.context.type;return")"!=b&&"]"!=b&&"}"!=b||(a.indented=a.context.indented),a.context=a.context.prev}function x(a,b,c){return"variable"==b.prevToken||"type"==b.prevToken||!!/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(a.string.slice(0,c))||!(!b.typeAtEndOfLine||a.column()!=a.indentation())||void 0}function f(a){for(;;){if(!a||"top"==a.type)return!0;if("}"==a.type&&"namespace"!=a.prev.info)return!1;a=a.prev}}function d(a){var b={};a=a.split(" ");for(var c=0;c<a.length;++c)b[a[c]]=!0;return b}function t(a,b){return"function"==
+typeof a?a(b):a.propertyIsEnumerable(b)}function u(a,b){if(!b.startOfLine)return!1;for(var c,d=null;c=a.peek();){if("\\"==c&&a.match(/^.$/)){d=u;break}if("/"==c&&a.match(/^\/[\/\*]/,!1))break;a.next()}return b.tokenize=d,"meta"}function n(a,b){return"type"==b.prevToken&&"type"}function y(a){return a.eatWhile(/[\w\.']/),"number"}function m(a,b){if(a.backUp(1),a.match(/(R|u8R|uR|UR|LR)/)){var c=a.match(/"([^\s\\()]{0,16})\(/);return!!c&&(b.cpp11RawStringDelim=c[1],b.tokenize=D,D(a,b))}return a.match(/(u8|u|U|L)/)?
+!!a.match(/["']/,!1)&&"string":(a.next(),!1)}function c(a,b){for(var c;null!=(c=a.next());)if('"'==c&&!a.eat('"')){b.tokenize=null;break}return"string"}function D(a,b){var c=b.cpp11RawStringDelim.replace(/[^\w\s]/g,"\\$\x26");return a.match(new RegExp(".*?\\)"+c+'"'))?b.tokenize=null:a.skipToEnd(),"string"}function z(a,b){function c(a){if(a)for(var b in a)a.hasOwnProperty(b)&&d.push(b)}"string"==typeof a&&(a=[a]);var d=[];c(b.keywords);c(b.types);c(b.builtin);c(b.atoms);d.length&&(b.helperType=a[0],
+e.registerHelper("hintWords",a[0],d));for(var f=0;f<a.length;++f)e.defineMIME(a[f],b)}function H(a,b){for(var c=!1;!a.eol();){if(!c&&a.match('"""')){b.tokenize=null;break}c="\\"==a.next()&&!c}return"string"}function v(a){return function(b,c){for(var d,e=!1,f=!1;!b.eol();){if(!a&&!e&&b.match('"')){f=!0;break}if(a&&b.match('"""')){f=!0;break}d=b.next();!e&&"$"==d&&b.match("{")&&b.skipTo("}");e=!e&&"\\"==d&&!a}return!f&&a||(c.tokenize=null),"string"}}function p(a){return function(b,c){for(var d,e=!1,
+f=!1;!b.eol();){if(!e&&b.match('"')&&("single"==a||b.match('""'))){f=!0;break}if(!e&&b.match("``")){k=p(a);f=!0;break}d=b.next();e="single"==a&&!e&&"\\"==d}return f&&(c.tokenize=null),"string"}}e.defineMode("clike",function(a,b){function c(a,b){var e=a.next();if(S[e]){var g=S[e](a,b);if(!1!==g)return g}if('"'==e||"'"==e)return b.tokenize=d(e),b.tokenize(a,b);if(J.test(e))return k=e,null;if(N.test(e)){if(a.backUp(1),a.match(R))return"number";a.next()}if("/"==e){if(a.eat("*"))return b.tokenize=n,n(a,
+b);if(a.eat("/"))return a.skipToEnd(),"comment"}if(P.test(e)){for(;!a.match(/^\/[\/*]/,!1)&&a.eat(P););return"operator"}if(a.eatWhile(G),O)for(;a.match(O);)a.eatWhile(G);e=a.current();return t(z,e)?(t(ca,e)&&(k="newstatement"),t(oa,e)&&(y=!0),"keyword"):t(D,e)?"type":t(H,e)?(t(ca,e)&&(k="newstatement"),"builtin"):t(ma,e)?"atom":"variable"}function d(a){return function(b,c){for(var d,e=!1,g=!1;null!=(d=b.next());){if(d==a&&!e){g=!0;break}e=!e&&"\\"==d}return(g||!e&&!aa)&&(c.tokenize=null),"string"}}
+function n(a,b){for(var c,d=!1;c=a.next();){if("/"==c&&d){b.tokenize=null;break}d="*"==c}return"comment"}function m(a,c){b.typeFirstDefinitions&&a.eol()&&f(c.context)&&(c.typeAtEndOfLine=x(a,c,a.pos))}var k,y,p=a.indentUnit,u=b.statementIndentUnit||p,v=b.dontAlignCalls,z=b.keywords||{},D=b.types||{},H=b.builtin||{},ca=b.blockKeywords||{},oa=b.defKeywords||{},ma=b.atoms||{},S=b.hooks||{},aa=b.multiLineStrings,pa=!1!==b.indentStatements,O=b.namespaceSeparator,J=b.isPunctuationChar||/[\[\]{}\(\),;\:\.]/,
+N=b.numberStart||/[\d\.]/,R=b.number||/^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,P=b.isOperatorChar||/[+\-*&%=<>!?|\/]/,G=b.isIdentifierChar||/[\w\$_\xa1-\uffff]/;return{startState:function(a){return{tokenize:null,context:new A((a||0)-p,0,"top",null,!1),indented:0,startOfLine:!0,prevToken:null}},token:function(a,d){var e=d.context;if(a.sol()&&(null==e.align&&(e.align=!1),d.indented=a.indentation(),d.startOfLine=!0),a.eatSpace())return m(a,d),null;k=y=null;var n=(d.tokenize||
+c)(a,d);if("comment"==n||"meta"==n)return n;if(null==e.align&&(e.align=!0),";"==k||":"==k||","==k&&a.match(/^\s*(?:\/\/.*)?$/,!1))for(;"statement"==d.context.type;)w(d);else if("{"==k)C(d,a.column(),"}");else if("["==k)C(d,a.column(),"]");else if("("==k)C(d,a.column(),")");else if("}"==k){for(;"statement"==e.type;)e=w(d);for("}"==e.type&&(e=w(d));"statement"==e.type;)e=w(d)}else k==e.type?w(d):pa&&(("}"==e.type||"top"==e.type)&&";"!=k||"statement"==e.type&&"newstatement"==k)&&C(d,a.column(),"statement",
+a.current());if("variable"==n&&("def"==d.prevToken||b.typeFirstDefinitions&&x(a,d,a.start)&&f(d.context)&&a.match(/^\s*\(/,!1))&&(n="def"),S.token)e=S.token(a,d,n),void 0!==e&&(n=e);return"def"==n&&!1===b.styleDefs&&(n="variable"),d.startOfLine=!1,d.prevToken=y?"def":n||k,m(a,d),n},indent:function(a,d){if(a.tokenize!=c&&null!=a.tokenize||a.typeAtEndOfLine)return e.Pass;var f=a.context,n=d&&d.charAt(0);if("statement"==f.type&&"}"==n&&(f=f.prev),b.dontIndentStatements)for(;"statement"==f.type&&b.dontIndentStatements.test(f.info);)f=
+f.prev;if(S.indent){var k=S.indent(a,f,d);if("number"==typeof k)return k}var k=n==f.type,h=f.prev&&"switch"==f.prev.info;if(b.allmanIndentation&&/[{(]/.test(n)){for(;"top"!=f.type&&"}"!=f.type;)f=f.prev;return f.indented}return"statement"==f.type?f.indented+("{"==n?0:u):!f.align||v&&")"==f.type?")"!=f.type||k?f.indented+(k?0:p)+(k||!h||/^(?:case|default)\b/.test(d)?0:p):f.indented+u:f.column+(k?0:1)},electricInput:!1!==b.indentSwitch?/^\s*(?:case .*?:|default:|\{\}?|\})$/:/^\s*[{}]$/,blockCommentStart:"/*",
+blockCommentEnd:"*/",lineComment:"//",fold:"brace"}});z(["text/x-csrc","text/x-c","text/x-chdr"],{name:"clike",keywords:d("auto if break case register continue return default do sizeof static else struct switch extern typedef union for goto while enum const volatile"),types:d("int long char short double float unsigned signed void size_t ptrdiff_t bool _Complex _Bool float_t double_t intptr_t intmax_t int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t uint32_t uint64_t"),blockKeywords:d("case do else for if switch while struct"),
+defKeywords:d("struct"),typeFirstDefinitions:!0,atoms:d("null true false"),hooks:{"#":u,"*":n},modeProps:{fold:["brace","include"]}});z(["text/x-c++src","text/x-c++hdr"],{name:"clike",keywords:d("auto if break case register continue return default do sizeof static else struct switch extern typedef union for goto while enum const volatile asm dynamic_cast namespace reinterpret_cast try explicit new static_cast typeid catch operator template typename class friend private this using const_cast inline public throw virtual delete mutable protected alignas alignof constexpr decltype nullptr noexcept thread_local final static_assert override"),
+types:d("int long char short double float unsigned signed void size_t ptrdiff_t bool wchar_t"),blockKeywords:d("catch class do else finally for if struct switch try while"),defKeywords:d("class namespace struct enum union"),typeFirstDefinitions:!0,atoms:d("true false null"),dontIndentStatements:/^template$/,isIdentifierChar:/[\w\$_~\xa1-\uffff]/,hooks:{"#":u,"*":n,u:m,U:m,L:m,R:m,0:y,1:y,2:y,3:y,4:y,5:y,6:y,7:y,8:y,9:y,token:function(a,b,c){if(b="variable"==c&&"("==a.peek()&&(";"==b.prevToken||null==
+b.prevToken||"}"==b.prevToken))a=a.current(),b=(a=/(\w+)::~?(\w+)$/.exec(a))&&a[1]==a[2];if(b)return"def"}},namespaceSeparator:"::",modeProps:{fold:["brace","include"]}});z("text/x-java",{name:"clike",keywords:d("abstract assert break case catch class const continue default do else enum extends final finally float for goto if implements import instanceof interface native new package private protected public return static strictfp super switch synchronized this throw throws transient try volatile while @interface"),
+types:d("byte short int long float double boolean char void Boolean Byte Character Double Float Integer Long Number Object Short String StringBuffer StringBuilder Void"),blockKeywords:d("catch class do else finally for if switch try while"),defKeywords:d("class interface package enum @interface"),typeFirstDefinitions:!0,atoms:d("true false null"),number:/^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,hooks:{"@":function(a){return!a.match("interface",!1)&&(a.eatWhile(/[\w\$_]/),
+"meta")}},modeProps:{fold:["brace","import"]}});z("text/x-csharp",{name:"clike",keywords:d("abstract as async await base break case catch checked class const continue default delegate do else enum event explicit extern finally fixed for foreach goto if implicit in interface internal is lock namespace new operator out override params private protected public readonly ref return sealed sizeof stackalloc static struct switch this throw try typeof unchecked unsafe using virtual void volatile while add alias ascending descending dynamic from get global group into join let orderby partial remove select set value var yield"),
+types:d("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32 UInt64 bool byte char decimal double short int long object sbyte float string ushort uint ulong"),blockKeywords:d("catch class do else finally for foreach if struct switch try while"),defKeywords:d("class interface namespace struct var"),typeFirstDefinitions:!0,atoms:d("true false null"),hooks:{"@":function(a,b){return a.eat('"')?(b.tokenize=c,
+c(a,b)):(a.eatWhile(/[\w\$_]/),"meta")}}});z("text/x-scala",{name:"clike",keywords:d("abstract case catch class def do else extends final finally for forSome if implicit import lazy match new null object override package private protected return sealed super this throw trait try type val var while with yield _ assert assume require print println printf readLine readBoolean readByte readShort readChar readInt readLong readFloat readDouble"),types:d("AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable Compiler Double Exception Float Integer Long Math Number Object Package Pair Process Runtime Runnable SecurityManager Short StackTraceElement StrictMath String StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"),
+multiLineStrings:!0,blockKeywords:d("catch class enum do else finally for forSome if match switch try while"),defKeywords:d("class enum def object package trait type val var"),atoms:d("true false null"),indentStatements:!1,indentSwitch:!1,isOperatorChar:/[+\-*&%=<>!?|\/#:@]/,hooks:{"@":function(a){return a.eatWhile(/[\w\$_]/),"meta"},'"':function(a,b){return!!a.match('""')&&(b.tokenize=H,b.tokenize(a,b))},"'":function(a){return a.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},"\x3d":function(a,b){var c=b.context;
+return!("}"!=c.type||!c.align||!a.eat("\x3e"))&&(b.context=new A(c.indented,c.column,c.type,c.info,null,c.prev),"operator")}},modeProps:{closeBrackets:{triples:'"'}}});z("text/x-kotlin",{name:"clike",keywords:d("package as typealias class interface this super val var fun for is in This throw return break continue object if else while do try when !in !is as? file import where by get set abstract enum open inner override private public internal protected catch finally out final vararg reified dynamic companion constructor init sealed field property receiver param sparam lateinit data inline noinline tailrec external annotation crossinline const operator infix suspend"),
+types:d("Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable Compiler Double Exception Float Integer Long Math Number Object Package Pair Process Runtime Runnable SecurityManager Short StackTraceElement StrictMath String StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"),intendSwitch:!1,indentStatements:!1,multiLineStrings:!0,number:/^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,blockKeywords:d("catch class do else finally for if where try while enum"),
+defKeywords:d("class val var object package interface fun"),atoms:d("true false null this"),hooks:{'"':function(a,b){return b.tokenize=v(a.match('""')),b.tokenize(a,b)}},modeProps:{closeBrackets:{triples:'"'}}});z(["x-shader/x-vertex","x-shader/x-fragment"],{name:"clike",keywords:d("sampler1D sampler2D sampler3D samplerCube sampler1DShadow sampler2DShadow const attribute uniform varying break continue discard return for while do if else struct in out inout"),types:d("float int bool void vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 mat2 mat3 mat4"),
+blockKeywords:d("for while do if else struct"),builtin:d("radians degrees sin cos tan asin acos atan pow exp log exp2 sqrt inversesqrt abs sign floor ceil fract mod min max clamp mix step smoothstep length distance dot cross normalize ftransform faceforward reflect refract matrixCompMult lessThan lessThanEqual greaterThan greaterThanEqual equal notEqual any all not texture1D texture1DProj texture1DLod texture1DProjLod texture2D texture2DProj texture2DLod texture2DProjLod texture3D texture3DProj texture3DLod texture3DProjLod textureCube textureCubeLod shadow1D shadow2D shadow1DProj shadow2DProj shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod dFdx dFdy fwidth noise1 noise2 noise3 noise4"),
+atoms:d("true false gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_FogCoord gl_PointCoord gl_Position gl_PointSize gl_ClipVertex gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_TexCoord gl_FogFragCoord gl_FragCoord gl_FrontFacing gl_FragData gl_FragDepth gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose gl_ProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixInverseTranspose gl_TextureMatrixInverseTranspose gl_NormalScale gl_DepthRange gl_ClipPlane gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel gl_FrontLightModelProduct gl_BackLightModelProduct gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ gl_FogParameters gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits gl_MaxDrawBuffers"),
+indentSwitch:!1,hooks:{"#":u},modeProps:{fold:["brace","include"]}});z("text/x-nesc",{name:"clike",keywords:d("auto if break case register continue return default do sizeof static else struct switch extern typedef union for goto while enum const volatileas atomic async call command component components configuration event generic implementation includes interface module new norace nx_struct nx_union post provides signal task uses abstract extends"),types:d("int long char short double float unsigned signed void size_t ptrdiff_t"),
+blockKeywords:d("case do else for if switch while struct"),atoms:d("null true false"),hooks:{"#":u},modeProps:{fold:["brace","include"]}});z("text/x-objectivec",{name:"clike",keywords:d("auto if break case register continue return default do sizeof static else struct switch extern typedef union for goto while enum const volatileinline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),
+types:d("int long char short double float unsigned signed void size_t ptrdiff_t"),atoms:d("YES NO NULL NILL ON OFF true false"),hooks:{"@":function(a){return a.eatWhile(/[\w\$]/),"keyword"},"#":u,indent:function(a,b,c){if("statement"==b.type&&/^@\w/.test(c))return b.indented}},modeProps:{fold:"brace"}});z("text/x-squirrel",{name:"clike",keywords:d("base break clone continue const default delete enum extends function in class foreach local resume return this throw typeof yield constructor instanceof static"),
+types:d("int long char short double float unsigned signed void size_t ptrdiff_t"),blockKeywords:d("case catch class else for foreach if switch try while"),defKeywords:d("function local class"),typeFirstDefinitions:!0,atoms:d("true false null"),hooks:{"#":u},modeProps:{fold:["brace","include"]}});var k=null;z("text/x-ceylon",{name:"clike",keywords:d("abstracts alias assembly assert assign break case catch class continue dynamic else exists extends finally for function given if import in interface is let module new nonempty object of out outer package return satisfies super switch then this throw try value void while"),
+types:function(a){a=a.charAt(0);return a===a.toUpperCase()&&a!==a.toLowerCase()},blockKeywords:d("case catch class dynamic else finally for function if interface module new object switch try while"),defKeywords:d("class dynamic function interface module object package value"),builtin:d("abstract actual aliased annotation by default deprecated doc final formal late license native optional sealed see serializable shared suppressWarnings tagged throws variable"),isPunctuationChar:/[\[\]{}\(\),;\:\.`]/,
+isOperatorChar:/[+\-*&%=<>!?|^~:\/]/,numberStart:/[\d#$]/,number:/^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,multiLineStrings:!0,typeFirstDefinitions:!0,atoms:d("true false null larger smaller equal empty finished"),indentSwitch:!1,styleDefs:!1,hooks:{"@":function(a){return a.eatWhile(/[\w\$_]/),"meta"},'"':function(a,b){return b.tokenize=p(a.match('""')?"triple":"single"),b.tokenize(a,b)},"`":function(a,b){return!(!k||!a.match("`"))&&(b.tokenize=
+k,k=null,b.tokenize(a,b))},"'":function(a){return a.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},token:function(a,b,c){if(("variable"==c||"type"==c)&&"."==b.prevToken)return"variable-2"}},modeProps:{fold:["brace","import"],closeBrackets:{triples:'"'}}})});
+(function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("../htmlmixed/htmlmixed"),require("../clike/clike")):"function"==typeof define&&define.amd?define("mode/php/php.js",["../../lib/codemirror","../htmlmixed/htmlmixed","../clike/clike"],e):e(CodeMirror)})(function(e){function A(e){var d={};e=e.split(" ");for(var t=0;t<e.length;++t)d[e[t]]=!0;return d}function C(e,d,t){return 0==e.length?w(d):function(u,n){for(var y=e[0],m=0;m<y.length;m++)if(u.match(y[m][0]))return n.tokenize=
+C(e.slice(1),d),y[m][1];return n.tokenize=w(d,t),"string"}}function w(e,d){return function(t,u){var n;if(!1!==d&&t.match("${",!1)||t.match("{$",!1))n=(u.tokenize=null,"string");else if(!1!==d&&t.match(/^\$[a-zA-Z_][a-zA-Z0-9_]*/))n=(t.match("[",!1)&&(u.tokenize=C([[["[",null]],[[/\d[\w\.]*/,"number"],[/\$[a-zA-Z_][a-zA-Z0-9_]*/,"variable-2"],[/[\w\$]+/,"variable"]],[["]",null]]],e,d)),t.match(/\-\>\w/,!1)&&(u.tokenize=C([[["-\x3e",null]],[[/[\w]+/,"variable"]]],e,d)),"variable-2");else{for(n=!1;!t.eol()&&
+(n||!1===d||!t.match("{$",!1)&&!t.match(/^(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{)/,!1));){if(!n&&t.match(e)){u.tokenize=null;u.tokStack.pop();u.tokStack.pop();break}n="\\"==t.next()&&!n}n="string"}return n}}e.registerHelper("hintWords","php","abstract and array as break case catch class clone const continue declare default do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final for foreach function global goto if implements interface instanceof namespace new or private protected public static switch throw trait try use var while xor die echo empty exit eval include include_once isset list require require_once return print unset __halt_compiler self static parent yield insteadof finally true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__ func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents file_put_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists array_intersect_key array_combine array_column pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count".split(" "));
+e.registerHelper("wordChars","php",/[\w$]/);var x={name:"clike",helperType:"php",keywords:A("abstract and array as break case catch class clone const continue declare default do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final for foreach function global goto if implements interface instanceof namespace new or private protected public static switch throw trait try use var while xor die echo empty exit eval include include_once isset list require require_once return print unset __halt_compiler self static parent yield insteadof finally"),
+blockKeywords:A("catch do else elseif for foreach if switch try while finally"),defKeywords:A("class function interface namespace trait"),atoms:A("true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__"),builtin:A("func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents file_put_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists array_intersect_key array_combine array_column pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count"),
+multiLineStrings:!0,hooks:{$:function(e){return e.eatWhile(/[\w\$_]/),"variable-2"},"\x3c":function(e,d){var t;if(t=e.match(/<<\s*/)){var u=e.eat(/['"]/);e.eatWhile(/[\w\.]/);t=e.current().slice(t[0].length+(u?2:1));if(u&&e.eat(u),t)return(d.tokStack||(d.tokStack=[])).push(t,0),d.tokenize=w(t,"'"!=u),"string"}return!1},"#":function(e){for(;!e.eol()&&!e.match("?\x3e",!1);)e.next();return"comment"},"/":function(e){if(e.eat("/")){for(;!e.eol()&&!e.match("?\x3e",!1);)e.next();return"comment"}return!1},
+'"':function(e,d){return(d.tokStack||(d.tokStack=[])).push('"',0),d.tokenize=w('"'),"string"},"{":function(e,d){return d.tokStack&&d.tokStack.length&&d.tokStack[d.tokStack.length-1]++,!1},"}":function(e,d){return d.tokStack&&0<d.tokStack.length&&!--d.tokStack[d.tokStack.length-1]&&(d.tokenize=w(d.tokStack[d.tokStack.length-2])),!1}}};e.defineMode("php",function(f,d){var t=e.getMode(f,"text/html"),u=e.getMode(f,x);return{startState:function(){var n=e.startState(t),f=d.startOpen?e.startState(u):null;
+return{html:n,php:f,curMode:d.startOpen?u:t,curState:d.startOpen?f:n,pending:null}},copyState:function(d){var f,m=e.copyState(t,d.html),c=d.php,c=c&&e.copyState(u,c);return f=d.curMode==t?m:c,{html:m,php:c,curMode:d.curMode,curState:f,pending:d.pending}},token:function(d,f){var m=f.curMode==u;if(d.sol()&&f.pending&&'"'!=f.pending&&"'"!=f.pending&&(f.pending=null),m)return m&&null==f.php.tokenize&&d.match("?\x3e")?(f.curMode=t,f.curState=f.html,f.php.context.prev||(f.php=null),"meta"):u.token(d,f.curState);
+if(d.match(/^<\?\w*/))return f.curMode=u,f.php||(f.php=e.startState(u,t.indent(f.html,""))),f.curState=f.php,"meta";if('"'==f.pending||"'"==f.pending){for(;!d.eol()&&d.next()!=f.pending;);m="string"}else f.pending&&d.pos<f.pending.end?(d.pos=f.pending.end,m=f.pending.style):m=t.token(d,f.curState);f.pending&&(f.pending=null);var c,w=d.current(),x=w.search(/<\?/);return-1!=x&&("string"==m&&(c=w.match(/[\'\"]$/))&&!/\?>/.test(w)?f.pending=c[0]:f.pending={end:d.pos,style:m},d.backUp(w.length-x)),m},
+indent:function(d,e){return d.curMode!=u&&/^\s*<\//.test(e)||d.curMode==u&&/^\?>/.test(e)?t.indent(d.html,e):d.curMode.indent(d.curState,e)},blockCommentStart:"/*",blockCommentEnd:"*/",lineComment:"//",innerMode:function(d){return{state:d.curState,mode:d.curMode}}}},"htmlmixed","clike");e.defineMIME("application/x-httpd-php","php");e.defineMIME("application/x-httpd-php-open",{name:"php",startOpen:!0});e.defineMIME("text/x-php",x)});
+(function(e){"function"==typeof e.define&&e.define("modePHP",["mode/php/php.js"],function(){})})(this);
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/js/codemirror.mode.twig.min.js b/js/ckeditor/plugins/codemirror/js/codemirror.mode.twig.min.js
new file mode 100644 (file)
index 0000000..0b98b10
--- /dev/null
@@ -0,0 +1,10 @@
+!function(f){"object"==typeof exports&&"object"==typeof module?f(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define("addon/mode/multiplex",["../../lib/codemirror"],f):f(CodeMirror)}(function(f){f.multiplexingMode=function(h){function k(a,d,c,b){return"string"==typeof d?(c=a.indexOf(d,c),b&&-1<c?c+d.length:c):(d=d.exec(c?a.slice(c):a))?d.index+c+(b?d[0].length:0):-1}var l=Array.prototype.slice.call(arguments,1);return{startState:function(){return{outer:f.startState(h),innerActive:null,
+inner:null}},copyState:function(a){return{outer:f.copyState(h,a.outer),innerActive:a.innerActive,inner:a.innerActive&&f.copyState(a.innerActive.mode,a.inner)}},token:function(a,d){if(d.innerActive){var c=d.innerActive,b=a.string;if(!c.close&&a.sol())return d.innerActive=d.inner=null,this.token(a,d);var e=c.close?k(b,c.close,a.pos,c.parseDelimiters):-1;if(e==a.pos&&!c.parseDelimiters)return a.match(c.close),d.innerActive=d.inner=null,c.delimStyle&&c.delimStyle+" "+c.delimStyle+"-close";-1<e&&(a.string=
+b.slice(0,e));var g=c.mode.token(a,d.inner);return-1<e&&(a.string=b),e==a.pos&&c.parseDelimiters&&(d.innerActive=d.inner=null),c.innerStyle&&(g=g?g+" "+c.innerStyle:c.innerStyle),g}c=1/0;b=a.string;for(g=0;g<l.length;++g){var m=l[g],e=k(b,m.open,a.pos);if(e==a.pos)return m.parseDelimiters||a.match(m.open),d.innerActive=m,d.inner=f.startState(m.mode,h.indent?h.indent(d.outer,""):0),m.delimStyle&&m.delimStyle+" "+m.delimStyle+"-open";-1!=e&&e<c&&(c=e)}c!=1/0&&(a.string=b.slice(0,c));e=h.token(a,d.outer);
+return c!=1/0&&(a.string=b),e},indent:function(a,d){var c=a.innerActive?a.innerActive.mode:h;return c.indent?c.indent(a.innerActive?a.inner:a.outer,d):f.Pass},blankLine:function(a){var d=a.innerActive?a.innerActive.mode:h;if(d.blankLine&&d.blankLine(a.innerActive?a.inner:a.outer),a.innerActive)"\n"===a.innerActive.close&&(a.innerActive=a.inner=null);else for(var c=0;c<l.length;++c){var b=l[c];"\n"===b.open&&(a.innerActive=b,a.inner=f.startState(b.mode,d.indent?d.indent(a.outer,""):0))}},electricChars:h.electricChars,
+innerMode:function(a){return a.inner?{state:a.inner,mode:a.innerActive.mode}:{state:a.outer,mode:h}}}}});
+(function(f){"object"==typeof exports&&"object"==typeof module?f(require("../../lib/codemirror"),require("../../addon/mode/multiplex")):"function"==typeof define&&define.amd?define("mode/twig/twig.js",["../../lib/codemirror","../../addon/mode/multiplex"],f):f(CodeMirror)})(function(f){f.defineMode("twig:inner",function(){function f(b,e){var g=b.peek();if(e.incomment)return b.skipTo("#}")?(b.eatWhile(/\#|}/),e.incomment=!1):b.skipToEnd(),"comment";if(e.intag){if(e.operator){if(e.operator=!1,b.match(d))return"atom";
+if(b.match(c))return"number"}if(e.sign){if(e.sign=!1,b.match(d))return"atom";if(b.match(c))return"number"}if(e.instring)return g==e.instring&&(e.instring=!1),b.next(),"string";if("'"==g||'"'==g)return e.instring=g,b.next(),"string";if(b.match(e.intag+"}")||b.eat("-")&&b.match(e.intag+"}"))return e.intag=!1,"tag";if(b.match(l))return e.operator=!0,"operator";if(b.match(a))e.sign=!0;else if(b.eat(" ")||b.sol()){if(b.match(k))return"keyword";if(b.match(d))return"atom";if(b.match(c))return"number";b.sol()&&
+b.next()}else b.next();return"variable"}if(b.eat("{")){if(b.eat("#"))return e.incomment=!0,b.skipTo("#}")?(b.eatWhile(/\#|}/),e.incomment=!1):b.skipToEnd(),"comment";if(g=b.eat(/\{|%/))return e.intag=g,"{"==g&&(e.intag="}"),b.eat("-"),"tag"}b.next()}var k="and as autoescape endautoescape block do endblock else elseif extends for endfor embed endembed filter endfilter flush from if endif in is include import not or set spaceless endspaceless with endwith trans endtrans blocktrans endblocktrans macro endmacro use verbatim endverbatim".split(" "),
+l=/^[+\-*&%=<>!?|~^]/,a=/^[:\[\(\{]/,d="true;false;null;empty;defined;divisibleby;divisible by;even;odd;iterable;sameas;same as".split(";"),c=/^(\d[+\-\*\/])?\d+(\.\d+)?/;return k=new RegExp("(("+k.join(")|(")+"))\\b"),d=new RegExp("(("+d.join(")|(")+"))\\b"),{startState:function(){return{}},token:function(a,c){return f(a,c)}}});f.defineMode("twig",function(h,k){var l=f.getMode(h,"twig:inner");return k&&k.base?f.multiplexingMode(f.getMode(h,k.base),{open:/\{[{#%]/,close:/[}#%]\}/,mode:l,parseDelimiters:!0}):
+l});f.defineMIME("text/x-twig","twig")});(function(f){"function"==typeof f.define&&f.define("modeTwig",["mode/twig/twig.js"],function(){})})(this);
\ No newline at end of file
diff --git a/js/ckeditor/plugins/codemirror/theme/3024-day.css b/js/ckeditor/plugins/codemirror/theme/3024-day.css
new file mode 100644 (file)
index 0000000..5232267
--- /dev/null
@@ -0,0 +1,41 @@
+/*\r
+\r
+    Name:       3024 day\r
+    Author:     Jan T. Sott (http://github.com/idleberg)\r
+\r
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\r
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\r
+\r
+*/\r
+\r
+.cm-s-3024-day.CodeMirror { background: #f7f7f7; color: #3a3432; }\r
+.cm-s-3024-day div.CodeMirror-selected { background: #d6d5d4; }\r
+\r
+.cm-s-3024-day .CodeMirror-line::selection, .cm-s-3024-day .CodeMirror-line > span::selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d6d5d4; }\r
+.cm-s-3024-day .CodeMirror-line::-moz-selection, .cm-s-3024-day .CodeMirror-line > span::-moz-selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d9d9d9; }\r
+\r
+.cm-s-3024-day .CodeMirror-gutters { background: #f7f7f7; border-right: 0px; }\r
+.cm-s-3024-day .CodeMirror-guttermarker { color: #db2d20; }\r
+.cm-s-3024-day .CodeMirror-guttermarker-subtle { color: #807d7c; }\r
+.cm-s-3024-day .CodeMirror-linenumber { color: #807d7c; }\r
+\r
+.cm-s-3024-day .CodeMirror-cursor { border-left: 1px solid #5c5855; }\r
+\r
+.cm-s-3024-day span.cm-comment { color: #cdab53; }\r
+.cm-s-3024-day span.cm-atom { color: #a16a94; }\r
+.cm-s-3024-day span.cm-number { color: #a16a94; }\r
+\r
+.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute { color: #01a252; }\r
+.cm-s-3024-day span.cm-keyword { color: #db2d20; }\r
+.cm-s-3024-day span.cm-string { color: #fded02; }\r
+\r
+.cm-s-3024-day span.cm-variable { color: #01a252; }\r
+.cm-s-3024-day span.cm-variable-2 { color: #01a0e4; }\r
+.cm-s-3024-day span.cm-def { color: #e8bbd0; }\r
+.cm-s-3024-day span.cm-bracket { color: #3a3432; }\r
+.cm-s-3024-day span.cm-tag { color: #db2d20; }\r
+.cm-s-3024-day span.cm-link { color: #a16a94; }\r
+.cm-s-3024-day span.cm-error { background: #db2d20; color: #5c5855; }\r
+\r
+.cm-s-3024-day .CodeMirror-activeline-background { background: #e8f2ff; }\r
+.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: #a16a94 !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/3024-night.css b/js/ckeditor/plugins/codemirror/theme/3024-night.css
new file mode 100644 (file)
index 0000000..bd0b64d
--- /dev/null
@@ -0,0 +1,39 @@
+/*\r
+\r
+    Name:       3024 night\r
+    Author:     Jan T. Sott (http://github.com/idleberg)\r
+\r
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\r
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\r
+\r
+*/\r
+\r
+.cm-s-3024-night.CodeMirror { background: #090300; color: #d6d5d4; }\r
+.cm-s-3024-night div.CodeMirror-selected { background: #3a3432; }\r
+.cm-s-3024-night .CodeMirror-line::selection, .cm-s-3024-night .CodeMirror-line > span::selection, .cm-s-3024-night .CodeMirror-line > span > span::selection { background: rgba(58, 52, 50, .99); }\r
+.cm-s-3024-night .CodeMirror-line::-moz-selection, .cm-s-3024-night .CodeMirror-line > span::-moz-selection, .cm-s-3024-night .CodeMirror-line > span > span::-moz-selection { background: rgba(58, 52, 50, .99); }\r
+.cm-s-3024-night .CodeMirror-gutters { background: #090300; border-right: 0px; }\r
+.cm-s-3024-night .CodeMirror-guttermarker { color: #db2d20; }\r
+.cm-s-3024-night .CodeMirror-guttermarker-subtle { color: #5c5855; }\r
+.cm-s-3024-night .CodeMirror-linenumber { color: #5c5855; }\r
+\r
+.cm-s-3024-night .CodeMirror-cursor { border-left: 1px solid #807d7c; }\r
+\r
+.cm-s-3024-night span.cm-comment { color: #cdab53; }\r
+.cm-s-3024-night span.cm-atom { color: #a16a94; }\r
+.cm-s-3024-night span.cm-number { color: #a16a94; }\r
+\r
+.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute { color: #01a252; }\r
+.cm-s-3024-night span.cm-keyword { color: #db2d20; }\r
+.cm-s-3024-night span.cm-string { color: #fded02; }\r
+\r
+.cm-s-3024-night span.cm-variable { color: #01a252; }\r
+.cm-s-3024-night span.cm-variable-2 { color: #01a0e4; }\r
+.cm-s-3024-night span.cm-def { color: #e8bbd0; }\r
+.cm-s-3024-night span.cm-bracket { color: #d6d5d4; }\r
+.cm-s-3024-night span.cm-tag { color: #db2d20; }\r
+.cm-s-3024-night span.cm-link { color: #a16a94; }\r
+.cm-s-3024-night span.cm-error { background: #db2d20; color: #807d7c; }\r
+\r
+.cm-s-3024-night .CodeMirror-activeline-background { background: #2F2F2F; }\r
+.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/abcdef.css b/js/ckeditor/plugins/codemirror/theme/abcdef.css
new file mode 100644 (file)
index 0000000..748540b
--- /dev/null
@@ -0,0 +1,32 @@
+.cm-s-abcdef.CodeMirror { background: #0f0f0f; color: #defdef; }\r
+.cm-s-abcdef div.CodeMirror-selected { background: #515151; }\r
+.cm-s-abcdef .CodeMirror-line::selection, .cm-s-abcdef .CodeMirror-line > span::selection, .cm-s-abcdef .CodeMirror-line > span > span::selection { background: rgba(56, 56, 56, 0.99); }\r
+.cm-s-abcdef .CodeMirror-line::-moz-selection, .cm-s-abcdef .CodeMirror-line > span::-moz-selection, .cm-s-abcdef .CodeMirror-line > span > span::-moz-selection { background: rgba(56, 56, 56, 0.99); }\r
+.cm-s-abcdef .CodeMirror-gutters { background: #555; border-right: 2px solid #314151; }\r
+.cm-s-abcdef .CodeMirror-guttermarker { color: #222; }\r
+.cm-s-abcdef .CodeMirror-guttermarker-subtle { color: azure; }\r
+.cm-s-abcdef .CodeMirror-linenumber { color: #FFFFFF; }\r
+.cm-s-abcdef .CodeMirror-cursor { border-left: 1px solid #00FF00; }\r
+\r
+.cm-s-abcdef span.cm-keyword { color: darkgoldenrod; font-weight: bold; }\r
+.cm-s-abcdef span.cm-atom { color: #77F; }\r
+.cm-s-abcdef span.cm-number { color: violet; }\r
+.cm-s-abcdef span.cm-def { color: #fffabc; }\r
+.cm-s-abcdef span.cm-variable { color: #abcdef; }\r
+.cm-s-abcdef span.cm-variable-2 { color: #cacbcc; }\r
+.cm-s-abcdef span.cm-variable-3, .cm-s-abcdef span.cm-type { color: #def; }\r
+.cm-s-abcdef span.cm-property { color: #fedcba; }\r
+.cm-s-abcdef span.cm-operator { color: #ff0; }\r
+.cm-s-abcdef span.cm-comment { color: #7a7b7c; font-style: italic;}\r
+.cm-s-abcdef span.cm-string { color: #2b4; }\r
+.cm-s-abcdef span.cm-meta { color: #C9F; }\r
+.cm-s-abcdef span.cm-qualifier { color: #FFF700; }\r
+.cm-s-abcdef span.cm-builtin { color: #30aabc; }\r
+.cm-s-abcdef span.cm-bracket { color: #8a8a8a; }\r
+.cm-s-abcdef span.cm-tag { color: #FFDD44; }\r
+.cm-s-abcdef span.cm-attribute { color: #DDFF00; }\r
+.cm-s-abcdef span.cm-error { color: #FF0000; }\r
+.cm-s-abcdef span.cm-header { color: aquamarine; font-weight: bold; }\r
+.cm-s-abcdef span.cm-link { color: blueviolet; }\r
+\r
+.cm-s-abcdef .CodeMirror-activeline-background { background: #314151; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/ambiance-mobile.css b/js/ckeditor/plugins/codemirror/theme/ambiance-mobile.css
new file mode 100644 (file)
index 0000000..374818a
--- /dev/null
@@ -0,0 +1,5 @@
+.cm-s-ambiance.CodeMirror {\r
+  -webkit-box-shadow: none;\r
+  -moz-box-shadow: none;\r
+  box-shadow: none;\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/ambiance.css b/js/ckeditor/plugins/codemirror/theme/ambiance.css
new file mode 100644 (file)
index 0000000..4d25e3f
--- /dev/null
@@ -0,0 +1,74 @@
+/* ambiance theme for codemirror */\r
+\r
+/* Color scheme */\r
+\r
+.cm-s-ambiance .cm-header { color: blue; }\r
+.cm-s-ambiance .cm-quote { color: #24C2C7; }\r
+\r
+.cm-s-ambiance .cm-keyword { color: #cda869; }\r
+.cm-s-ambiance .cm-atom { color: #CF7EA9; }\r
+.cm-s-ambiance .cm-number { color: #78CF8A; }\r
+.cm-s-ambiance .cm-def { color: #aac6e3; }\r
+.cm-s-ambiance .cm-variable { color: #ffb795; }\r
+.cm-s-ambiance .cm-variable-2 { color: #eed1b3; }\r
+.cm-s-ambiance .cm-variable-3, .cm-s-ambiance .cm-type { color: #faded3; }\r
+.cm-s-ambiance .cm-property { color: #eed1b3; }\r
+.cm-s-ambiance .cm-operator { color: #fa8d6a; }\r
+.cm-s-ambiance .cm-comment { color: #555; font-style:italic; }\r
+.cm-s-ambiance .cm-string { color: #8f9d6a; }\r
+.cm-s-ambiance .cm-string-2 { color: #9d937c; }\r
+.cm-s-ambiance .cm-meta { color: #D2A8A1; }\r
+.cm-s-ambiance .cm-qualifier { color: yellow; }\r
+.cm-s-ambiance .cm-builtin { color: #9999cc; }\r
+.cm-s-ambiance .cm-bracket { color: #24C2C7; }\r
+.cm-s-ambiance .cm-tag { color: #fee4ff; }\r
+.cm-s-ambiance .cm-attribute { color: #9B859D; }\r
+.cm-s-ambiance .cm-hr { color: pink; }\r
+.cm-s-ambiance .cm-link { color: #F4C20B; }\r
+.cm-s-ambiance .cm-special { color: #FF9D00; }\r
+.cm-s-ambiance .cm-error { color: #AF2018; }\r
+\r
+.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; }\r
+.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; }\r
+\r
+.cm-s-ambiance div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }\r
+.cm-s-ambiance.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-ambiance .CodeMirror-line::selection, .cm-s-ambiance .CodeMirror-line > span::selection, .cm-s-ambiance .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-ambiance .CodeMirror-line::-moz-selection, .cm-s-ambiance .CodeMirror-line > span::-moz-selection, .cm-s-ambiance .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }\r
+\r
+/* Editor styling */\r
+\r
+.cm-s-ambiance.CodeMirror {\r
+  line-height: 1.40em;\r
+  color: #E6E1DC;\r
+  background-color: #202020;\r
+  -webkit-box-shadow: inset 0 0 10px black;\r
+  -moz-box-shadow: inset 0 0 10px black;\r
+  box-shadow: inset 0 0 10px black;\r
+}\r
+\r
+.cm-s-ambiance .CodeMirror-gutters {\r
+  background: #3D3D3D;\r
+  border-right: 1px solid #4D4D4D;\r
+  box-shadow: 0 10px 20px black;\r
+}\r
+\r
+.cm-s-ambiance .CodeMirror-linenumber {\r
+  text-shadow: 0px 1px 1px #4d4d4d;\r
+  color: #111;\r
+  padding: 0 5px;\r
+}\r
+\r
+.cm-s-ambiance .CodeMirror-guttermarker { color: #aaa; }\r
+.cm-s-ambiance .CodeMirror-guttermarker-subtle { color: #111; }\r
+\r
+.cm-s-ambiance .CodeMirror-cursor { border-left: 1px solid #7991E8; }\r
+\r
+.cm-s-ambiance .CodeMirror-activeline-background {\r
+  background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031);\r
+}\r
+\r
+.cm-s-ambiance.CodeMirror,\r
+.cm-s-ambiance .CodeMirror-gutters {\r
+  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC");\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/base16-dark.css b/js/ckeditor/plugins/codemirror/theme/base16-dark.css
new file mode 100644 (file)
index 0000000..c35a38d
--- /dev/null
@@ -0,0 +1,38 @@
+/*\r
+\r
+    Name:       Base16 Default Dark\r
+    Author:     Chris Kempson (http://chriskempson.com)\r
+\r
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\r
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\r
+\r
+*/\r
+\r
+.cm-s-base16-dark.CodeMirror { background: #151515; color: #e0e0e0; }\r
+.cm-s-base16-dark div.CodeMirror-selected { background: #303030; }\r
+.cm-s-base16-dark .CodeMirror-line::selection, .cm-s-base16-dark .CodeMirror-line > span::selection, .cm-s-base16-dark .CodeMirror-line > span > span::selection { background: rgba(48, 48, 48, .99); }\r
+.cm-s-base16-dark .CodeMirror-line::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(48, 48, 48, .99); }\r
+.cm-s-base16-dark .CodeMirror-gutters { background: #151515; border-right: 0px; }\r
+.cm-s-base16-dark .CodeMirror-guttermarker { color: #ac4142; }\r
+.cm-s-base16-dark .CodeMirror-guttermarker-subtle { color: #505050; }\r
+.cm-s-base16-dark .CodeMirror-linenumber { color: #505050; }\r
+.cm-s-base16-dark .CodeMirror-cursor { border-left: 1px solid #b0b0b0; }\r
+\r
+.cm-s-base16-dark span.cm-comment { color: #8f5536; }\r
+.cm-s-base16-dark span.cm-atom { color: #aa759f; }\r
+.cm-s-base16-dark span.cm-number { color: #aa759f; }\r
+\r
+.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute { color: #90a959; }\r
+.cm-s-base16-dark span.cm-keyword { color: #ac4142; }\r
+.cm-s-base16-dark span.cm-string { color: #f4bf75; }\r
+\r
+.cm-s-base16-dark span.cm-variable { color: #90a959; }\r
+.cm-s-base16-dark span.cm-variable-2 { color: #6a9fb5; }\r
+.cm-s-base16-dark span.cm-def { color: #d28445; }\r
+.cm-s-base16-dark span.cm-bracket { color: #e0e0e0; }\r
+.cm-s-base16-dark span.cm-tag { color: #ac4142; }\r
+.cm-s-base16-dark span.cm-link { color: #aa759f; }\r
+.cm-s-base16-dark span.cm-error { background: #ac4142; color: #b0b0b0; }\r
+\r
+.cm-s-base16-dark .CodeMirror-activeline-background { background: #202020; }\r
+.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/base16-light.css b/js/ckeditor/plugins/codemirror/theme/base16-light.css
new file mode 100644 (file)
index 0000000..5561f8c
--- /dev/null
@@ -0,0 +1,38 @@
+/*\r
+\r
+    Name:       Base16 Default Light\r
+    Author:     Chris Kempson (http://chriskempson.com)\r
+\r
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\r
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\r
+\r
+*/\r
+\r
+.cm-s-base16-light.CodeMirror { background: #f5f5f5; color: #202020; }\r
+.cm-s-base16-light div.CodeMirror-selected { background: #e0e0e0; }\r
+.cm-s-base16-light .CodeMirror-line::selection, .cm-s-base16-light .CodeMirror-line > span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; }\r
+.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; }\r
+.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; }\r
+.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; }\r
+.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; }\r
+.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; }\r
+.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; }\r
+\r
+.cm-s-base16-light span.cm-comment { color: #8f5536; }\r
+.cm-s-base16-light span.cm-atom { color: #aa759f; }\r
+.cm-s-base16-light span.cm-number { color: #aa759f; }\r
+\r
+.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #90a959; }\r
+.cm-s-base16-light span.cm-keyword { color: #ac4142; }\r
+.cm-s-base16-light span.cm-string { color: #f4bf75; }\r
+\r
+.cm-s-base16-light span.cm-variable { color: #90a959; }\r
+.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; }\r
+.cm-s-base16-light span.cm-def { color: #d28445; }\r
+.cm-s-base16-light span.cm-bracket { color: #202020; }\r
+.cm-s-base16-light span.cm-tag { color: #ac4142; }\r
+.cm-s-base16-light span.cm-link { color: #aa759f; }\r
+.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; }\r
+\r
+.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; }\r
+.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/bespin.css b/js/ckeditor/plugins/codemirror/theme/bespin.css
new file mode 100644 (file)
index 0000000..becfad9
--- /dev/null
@@ -0,0 +1,34 @@
+/*\r
+\r
+    Name:       Bespin\r
+    Author:     Mozilla / Jan T. Sott\r
+\r
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\r
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\r
+\r
+*/\r
+\r
+.cm-s-bespin.CodeMirror {background: #28211c; color: #9d9b97;}\r
+.cm-s-bespin div.CodeMirror-selected {background: #36312e !important;}\r
+.cm-s-bespin .CodeMirror-gutters {background: #28211c; border-right: 0px;}\r
+.cm-s-bespin .CodeMirror-linenumber {color: #666666;}\r
+.cm-s-bespin .CodeMirror-cursor {border-left: 1px solid #797977 !important;}\r
+\r
+.cm-s-bespin span.cm-comment {color: #937121;}\r
+.cm-s-bespin span.cm-atom {color: #9b859d;}\r
+.cm-s-bespin span.cm-number {color: #9b859d;}\r
+\r
+.cm-s-bespin span.cm-property, .cm-s-bespin span.cm-attribute {color: #54be0d;}\r
+.cm-s-bespin span.cm-keyword {color: #cf6a4c;}\r
+.cm-s-bespin span.cm-string {color: #f9ee98;}\r
+\r
+.cm-s-bespin span.cm-variable {color: #54be0d;}\r
+.cm-s-bespin span.cm-variable-2 {color: #5ea6ea;}\r
+.cm-s-bespin span.cm-def {color: #cf7d34;}\r
+.cm-s-bespin span.cm-error {background: #cf6a4c; color: #797977;}\r
+.cm-s-bespin span.cm-bracket {color: #9d9b97;}\r
+.cm-s-bespin span.cm-tag {color: #cf6a4c;}\r
+.cm-s-bespin span.cm-link {color: #9b859d;}\r
+\r
+.cm-s-bespin .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\r
+.cm-s-bespin .CodeMirror-activeline-background { background: #404040; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/blackboard.css b/js/ckeditor/plugins/codemirror/theme/blackboard.css
new file mode 100644 (file)
index 0000000..0fa55e7
--- /dev/null
@@ -0,0 +1,32 @@
+/* Port of TextMate's Blackboard theme */\r
+\r
+.cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; }\r
+.cm-s-blackboard div.CodeMirror-selected { background: #253B76; }\r
+.cm-s-blackboard .CodeMirror-line::selection, .cm-s-blackboard .CodeMirror-line > span::selection, .cm-s-blackboard .CodeMirror-line > span > span::selection { background: rgba(37, 59, 118, .99); }\r
+.cm-s-blackboard .CodeMirror-line::-moz-selection, .cm-s-blackboard .CodeMirror-line > span::-moz-selection, .cm-s-blackboard .CodeMirror-line > span > span::-moz-selection { background: rgba(37, 59, 118, .99); }\r
+.cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; }\r
+.cm-s-blackboard .CodeMirror-guttermarker { color: #FBDE2D; }\r
+.cm-s-blackboard .CodeMirror-guttermarker-subtle { color: #888; }\r
+.cm-s-blackboard .CodeMirror-linenumber { color: #888; }\r
+.cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7; }\r
+\r
+.cm-s-blackboard .cm-keyword { color: #FBDE2D; }\r
+.cm-s-blackboard .cm-atom { color: #D8FA3C; }\r
+.cm-s-blackboard .cm-number { color: #D8FA3C; }\r
+.cm-s-blackboard .cm-def { color: #8DA6CE; }\r
+.cm-s-blackboard .cm-variable { color: #FF6400; }\r
+.cm-s-blackboard .cm-operator { color: #FBDE2D; }\r
+.cm-s-blackboard .cm-comment { color: #AEAEAE; }\r
+.cm-s-blackboard .cm-string { color: #61CE3C; }\r
+.cm-s-blackboard .cm-string-2 { color: #61CE3C; }\r
+.cm-s-blackboard .cm-meta { color: #D8FA3C; }\r
+.cm-s-blackboard .cm-builtin { color: #8DA6CE; }\r
+.cm-s-blackboard .cm-tag { color: #8DA6CE; }\r
+.cm-s-blackboard .cm-attribute { color: #8DA6CE; }\r
+.cm-s-blackboard .cm-header { color: #FF6400; }\r
+.cm-s-blackboard .cm-hr { color: #AEAEAE; }\r
+.cm-s-blackboard .cm-link { color: #8DA6CE; }\r
+.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }\r
+\r
+.cm-s-blackboard .CodeMirror-activeline-background { background: #3C3636; }\r
+.cm-s-blackboard .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/cobalt.css b/js/ckeditor/plugins/codemirror/theme/cobalt.css
new file mode 100644 (file)
index 0000000..bf24bd2
--- /dev/null
@@ -0,0 +1,25 @@
+.cm-s-cobalt.CodeMirror { background: #002240; color: white; }\r
+.cm-s-cobalt div.CodeMirror-selected { background: #b36539; }\r
+.cm-s-cobalt .CodeMirror-line::selection, .cm-s-cobalt .CodeMirror-line > span::selection, .cm-s-cobalt .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); }\r
+.cm-s-cobalt .CodeMirror-line::-moz-selection, .cm-s-cobalt .CodeMirror-line > span::-moz-selection, .cm-s-cobalt .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); }\r
+.cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }\r
+.cm-s-cobalt .CodeMirror-guttermarker { color: #ffee80; }\r
+.cm-s-cobalt .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\r
+.cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; }\r
+.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white; }\r
+\r
+.cm-s-cobalt span.cm-comment { color: #08f; }\r
+.cm-s-cobalt span.cm-atom { color: #845dc4; }\r
+.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; }\r
+.cm-s-cobalt span.cm-keyword { color: #ffee80; }\r
+.cm-s-cobalt span.cm-string { color: #3ad900; }\r
+.cm-s-cobalt span.cm-meta { color: #ff9d00; }\r
+.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }\r
+.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def, .cm-s-cobalt .cm-type { color: white; }\r
+.cm-s-cobalt span.cm-bracket { color: #d8d8d8; }\r
+.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }\r
+.cm-s-cobalt span.cm-link { color: #845dc4; }\r
+.cm-s-cobalt span.cm-error { color: #9d1e15; }\r
+\r
+.cm-s-cobalt .CodeMirror-activeline-background { background: #002D57; }\r
+.cm-s-cobalt .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/colorforth.css b/js/ckeditor/plugins/codemirror/theme/colorforth.css
new file mode 100644 (file)
index 0000000..a096504
--- /dev/null
@@ -0,0 +1,33 @@
+.cm-s-colorforth.CodeMirror { background: #000000; color: #f8f8f8; }\r
+.cm-s-colorforth .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }\r
+.cm-s-colorforth .CodeMirror-guttermarker { color: #FFBD40; }\r
+.cm-s-colorforth .CodeMirror-guttermarker-subtle { color: #78846f; }\r
+.cm-s-colorforth .CodeMirror-linenumber { color: #bababa; }\r
+.cm-s-colorforth .CodeMirror-cursor { border-left: 1px solid white; }\r
+\r
+.cm-s-colorforth span.cm-comment     { color: #ededed; }\r
+.cm-s-colorforth span.cm-def         { color: #ff1c1c; font-weight:bold; }\r
+.cm-s-colorforth span.cm-keyword     { color: #ffd900; }\r
+.cm-s-colorforth span.cm-builtin     { color: #00d95a; }\r
+.cm-s-colorforth span.cm-variable    { color: #73ff00; }\r
+.cm-s-colorforth span.cm-string      { color: #007bff; }\r
+.cm-s-colorforth span.cm-number      { color: #00c4ff; }\r
+.cm-s-colorforth span.cm-atom        { color: #606060; }\r
+\r
+.cm-s-colorforth span.cm-variable-2  { color: #EEE; }\r
+.cm-s-colorforth span.cm-variable-3, .cm-s-colorforth span.cm-type { color: #DDD; }\r
+.cm-s-colorforth span.cm-property    {}\r
+.cm-s-colorforth span.cm-operator    {}\r
+\r
+.cm-s-colorforth span.cm-meta        { color: yellow; }\r
+.cm-s-colorforth span.cm-qualifier   { color: #FFF700; }\r
+.cm-s-colorforth span.cm-bracket     { color: #cc7; }\r
+.cm-s-colorforth span.cm-tag         { color: #FFBD40; }\r
+.cm-s-colorforth span.cm-attribute   { color: #FFF700; }\r
+.cm-s-colorforth span.cm-error       { color: #f00; }\r
+\r
+.cm-s-colorforth div.CodeMirror-selected { background: #333d53; }\r
+\r
+.cm-s-colorforth span.cm-compilation { background: rgba(255, 255, 255, 0.12); }\r
+\r
+.cm-s-colorforth .CodeMirror-activeline-background { background: #253540; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/dracula.css b/js/ckeditor/plugins/codemirror/theme/dracula.css
new file mode 100644 (file)
index 0000000..cc41554
--- /dev/null
@@ -0,0 +1,40 @@
+/*\r
+\r
+    Name:       dracula\r
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)\r
+\r
+    Original dracula color scheme by Zeno Rocha (https://github.com/zenorocha/dracula-theme)\r
+\r
+*/\r
+\r
+\r
+.cm-s-dracula.CodeMirror, .cm-s-dracula .CodeMirror-gutters {\r
+  background-color: #282a36 !important;\r
+  color: #f8f8f2 !important;\r
+  border: none;\r
+}\r
+.cm-s-dracula .CodeMirror-gutters { color: #282a36; }\r
+.cm-s-dracula .CodeMirror-cursor { border-left: solid thin #f8f8f0; }\r
+.cm-s-dracula .CodeMirror-linenumber { color: #6D8A88; }\r
+.cm-s-dracula .CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-dracula .CodeMirror-line::selection, .cm-s-dracula .CodeMirror-line > span::selection, .cm-s-dracula .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-dracula .CodeMirror-line::-moz-selection, .cm-s-dracula .CodeMirror-line > span::-moz-selection, .cm-s-dracula .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-dracula span.cm-comment { color: #6272a4; }\r
+.cm-s-dracula span.cm-string, .cm-s-dracula span.cm-string-2 { color: #f1fa8c; }\r
+.cm-s-dracula span.cm-number { color: #bd93f9; }\r
+.cm-s-dracula span.cm-variable { color: #50fa7b; }\r
+.cm-s-dracula span.cm-variable-2 { color: white; }\r
+.cm-s-dracula span.cm-def { color: #50fa7b; }\r
+.cm-s-dracula span.cm-operator { color: #ff79c6; }\r
+.cm-s-dracula span.cm-keyword { color: #ff79c6; }\r
+.cm-s-dracula span.cm-atom { color: #bd93f9; }\r
+.cm-s-dracula span.cm-meta { color: #f8f8f2; }\r
+.cm-s-dracula span.cm-tag { color: #ff79c6; }\r
+.cm-s-dracula span.cm-attribute { color: #50fa7b; }\r
+.cm-s-dracula span.cm-qualifier { color: #50fa7b; }\r
+.cm-s-dracula span.cm-property { color: #66d9ef; }\r
+.cm-s-dracula span.cm-builtin { color: #50fa7b; }\r
+.cm-s-dracula span.cm-variable-3, .cm-s-dracula span.cm-type { color: #ffb86c; }\r
+\r
+.cm-s-dracula .CodeMirror-activeline-background { background: rgba(255,255,255,0.1); }\r
+.cm-s-dracula .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/duotone-dark.css b/js/ckeditor/plugins/codemirror/theme/duotone-dark.css
new file mode 100644 (file)
index 0000000..a493eb6
--- /dev/null
@@ -0,0 +1,35 @@
+/*\r
+Name:   DuoTone-Dark\r
+Author: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)\r
+\r
+CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/)\r
+*/\r
+\r
+.cm-s-duotone-dark.CodeMirror { background: #2a2734; color: #6c6783; }\r
+.cm-s-duotone-dark div.CodeMirror-selected { background: #545167!important; }\r
+.cm-s-duotone-dark .CodeMirror-gutters { background: #2a2734; border-right: 0px; }\r
+.cm-s-duotone-dark .CodeMirror-linenumber { color: #545167; }\r
+\r
+/* begin cursor */\r
+.cm-s-duotone-dark .CodeMirror-cursor { border-left: 1px solid #ffad5c; /* border-left: 1px solid #ffad5c80; */ border-right: .5em solid #ffad5c; /* border-right: .5em solid #ffad5c80; */ opacity: .5; }\r
+.cm-s-duotone-dark .CodeMirror-activeline-background { background: #363342; /* background: #36334280;  */ opacity: .5;}\r
+.cm-s-duotone-dark .cm-fat-cursor .CodeMirror-cursor { background: #ffad5c; /* background: #ffad5c80; */ opacity: .5;}\r
+/* end cursor */\r
+\r
+.cm-s-duotone-dark span.cm-atom, .cm-s-duotone-dark span.cm-number, .cm-s-duotone-dark span.cm-keyword, .cm-s-duotone-dark span.cm-variable, .cm-s-duotone-dark span.cm-attribute, .cm-s-duotone-dark span.cm-quote, .cm-s-duotone-dark span.cm-hr, .cm-s-duotone-dark span.cm-link { color: #ffcc99; }\r
+\r
+.cm-s-duotone-dark span.cm-property { color: #9a86fd; }\r
+.cm-s-duotone-dark span.cm-punctuation, .cm-s-duotone-dark span.cm-unit, .cm-s-duotone-dark span.cm-negative { color: #e09142; }\r
+.cm-s-duotone-dark span.cm-string { color: #ffb870; }\r
+.cm-s-duotone-dark span.cm-operator { color: #ffad5c; }\r
+.cm-s-duotone-dark span.cm-positive { color: #6a51e6; }\r
+\r
+.cm-s-duotone-dark span.cm-variable-2, .cm-s-duotone-dark span.cm-variable-3, .cm-s-duotone-dark span.cm-type, .cm-s-duotone-dark span.cm-string-2, .cm-s-duotone-dark span.cm-url { color: #7a63ee; }\r
+.cm-s-duotone-dark span.cm-def, .cm-s-duotone-dark span.cm-tag, .cm-s-duotone-dark span.cm-builtin, .cm-s-duotone-dark span.cm-qualifier, .cm-s-duotone-dark span.cm-header, .cm-s-duotone-dark span.cm-em { color: #eeebff; }\r
+.cm-s-duotone-dark span.cm-bracket, .cm-s-duotone-dark span.cm-comment { color: #6c6783; }\r
+\r
+/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */\r
+.cm-s-duotone-dark span.cm-error, .cm-s-duotone-dark span.cm-invalidchar { color: #f00; }\r
+\r
+.cm-s-duotone-dark span.cm-header { font-weight: normal; }\r
+.cm-s-duotone-dark .CodeMirror-matchingbracket { text-decoration: underline; color: #eeebff !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/duotone-light.css b/js/ckeditor/plugins/codemirror/theme/duotone-light.css
new file mode 100644 (file)
index 0000000..68db16e
--- /dev/null
@@ -0,0 +1,35 @@
+/*\r
+Name:   DuoTone-Light\r
+Author: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)\r
+\r
+CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/)\r
+*/\r
+\r
+.cm-s-duotone-light.CodeMirror { background: #faf8f5; color: #b29762; }\r
+.cm-s-duotone-light div.CodeMirror-selected { background: #e3dcce !important; }\r
+.cm-s-duotone-light .CodeMirror-gutters { background: #faf8f5; border-right: 0px; }\r
+.cm-s-duotone-light .CodeMirror-linenumber { color: #cdc4b1; }\r
+\r
+/* begin cursor */\r
+.cm-s-duotone-light .CodeMirror-cursor { border-left: 1px solid #93abdc; /* border-left: 1px solid #93abdc80; */ border-right: .5em solid #93abdc; /* border-right: .5em solid #93abdc80; */ opacity: .5; }\r
+.cm-s-duotone-light .CodeMirror-activeline-background { background: #e3dcce;  /* background: #e3dcce80; */ opacity: .5; }\r
+.cm-s-duotone-light .cm-fat-cursor .CodeMirror-cursor { background: #93abdc; /* #93abdc80; */ opacity: .5; }\r
+/* end cursor */\r
+\r
+.cm-s-duotone-light span.cm-atom, .cm-s-duotone-light span.cm-number, .cm-s-duotone-light span.cm-keyword, .cm-s-duotone-light span.cm-variable, .cm-s-duotone-light span.cm-attribute, .cm-s-duotone-light span.cm-quote, .cm-s-duotone-light-light span.cm-hr, .cm-s-duotone-light-light span.cm-link { color: #063289; }\r
+\r
+.cm-s-duotone-light span.cm-property { color: #b29762; }\r
+.cm-s-duotone-light span.cm-punctuation, .cm-s-duotone-light span.cm-unit, .cm-s-duotone-light span.cm-negative { color: #063289; }\r
+.cm-s-duotone-light span.cm-string, .cm-s-duotone-light span.cm-operator { color: #1659df; }\r
+.cm-s-duotone-light span.cm-positive { color: #896724; }\r
+\r
+.cm-s-duotone-light span.cm-variable-2, .cm-s-duotone-light span.cm-variable-3, .cm-s-duotone-light span.cm-type, .cm-s-duotone-light span.cm-string-2, .cm-s-duotone-light span.cm-url { color: #896724; }\r
+.cm-s-duotone-light span.cm-def, .cm-s-duotone-light span.cm-tag, .cm-s-duotone-light span.cm-builtin, .cm-s-duotone-light span.cm-qualifier, .cm-s-duotone-light span.cm-header, .cm-s-duotone-light span.cm-em { color: #2d2006; }\r
+.cm-s-duotone-light span.cm-bracket, .cm-s-duotone-light span.cm-comment { color: #b6ad9a; }\r
+\r
+/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */\r
+/* .cm-s-duotone-light span.cm-error { background: #896724; color: #728fcb; } */\r
+.cm-s-duotone-light span.cm-error, .cm-s-duotone-light span.cm-invalidchar { color: #f00; }\r
+\r
+.cm-s-duotone-light span.cm-header { font-weight: normal; }\r
+.cm-s-duotone-light .CodeMirror-matchingbracket { text-decoration: underline; color: #faf8f5 !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/eclipse.css b/js/ckeditor/plugins/codemirror/theme/eclipse.css
new file mode 100644 (file)
index 0000000..30fe9d1
--- /dev/null
@@ -0,0 +1,23 @@
+.cm-s-eclipse span.cm-meta { color: #FF1717; }\r
+.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }\r
+.cm-s-eclipse span.cm-atom { color: #219; }\r
+.cm-s-eclipse span.cm-number { color: #164; }\r
+.cm-s-eclipse span.cm-def { color: #00f; }\r
+.cm-s-eclipse span.cm-variable { color: black; }\r
+.cm-s-eclipse span.cm-variable-2 { color: #0000C0; }\r
+.cm-s-eclipse span.cm-variable-3, .cm-s-eclipse span.cm-type { color: #0000C0; }\r
+.cm-s-eclipse span.cm-property { color: black; }\r
+.cm-s-eclipse span.cm-operator { color: black; }\r
+.cm-s-eclipse span.cm-comment { color: #3F7F5F; }\r
+.cm-s-eclipse span.cm-string { color: #2A00FF; }\r
+.cm-s-eclipse span.cm-string-2 { color: #f50; }\r
+.cm-s-eclipse span.cm-qualifier { color: #555; }\r
+.cm-s-eclipse span.cm-builtin { color: #30a; }\r
+.cm-s-eclipse span.cm-bracket { color: #cc7; }\r
+.cm-s-eclipse span.cm-tag { color: #170; }\r
+.cm-s-eclipse span.cm-attribute { color: #00c; }\r
+.cm-s-eclipse span.cm-link { color: #219; }\r
+.cm-s-eclipse span.cm-error { color: #f00; }\r
+\r
+.cm-s-eclipse .CodeMirror-activeline-background { background: #e8f2ff; }\r
+.cm-s-eclipse .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/elegant.css b/js/ckeditor/plugins/codemirror/theme/elegant.css
new file mode 100644 (file)
index 0000000..a5929c1
--- /dev/null
@@ -0,0 +1,13 @@
+.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom { color: #762; }\r
+.cm-s-elegant span.cm-comment { color: #262; font-style: italic; line-height: 1em; }\r
+.cm-s-elegant span.cm-meta { color: #555; font-style: italic; line-height: 1em; }\r
+.cm-s-elegant span.cm-variable { color: black; }\r
+.cm-s-elegant span.cm-variable-2 { color: #b11; }\r
+.cm-s-elegant span.cm-qualifier { color: #555; }\r
+.cm-s-elegant span.cm-keyword { color: #730; }\r
+.cm-s-elegant span.cm-builtin { color: #30a; }\r
+.cm-s-elegant span.cm-link { color: #762; }\r
+.cm-s-elegant span.cm-error { background-color: #fdd; }\r
+\r
+.cm-s-elegant .CodeMirror-activeline-background { background: #e8f2ff; }\r
+.cm-s-elegant .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/erlang-dark.css b/js/ckeditor/plugins/codemirror/theme/erlang-dark.css
new file mode 100644 (file)
index 0000000..35e8796
--- /dev/null
@@ -0,0 +1,34 @@
+.cm-s-erlang-dark.CodeMirror { background: #002240; color: white; }\r
+.cm-s-erlang-dark div.CodeMirror-selected { background: #b36539; }\r
+.cm-s-erlang-dark .CodeMirror-line::selection, .cm-s-erlang-dark .CodeMirror-line > span::selection, .cm-s-erlang-dark .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); }\r
+.cm-s-erlang-dark .CodeMirror-line::-moz-selection, .cm-s-erlang-dark .CodeMirror-line > span::-moz-selection, .cm-s-erlang-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); }\r
+.cm-s-erlang-dark .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }\r
+.cm-s-erlang-dark .CodeMirror-guttermarker { color: white; }\r
+.cm-s-erlang-dark .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\r
+.cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; }\r
+.cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white; }\r
+\r
+.cm-s-erlang-dark span.cm-quote      { color: #ccc; }\r
+.cm-s-erlang-dark span.cm-atom       { color: #f133f1; }\r
+.cm-s-erlang-dark span.cm-attribute  { color: #ff80e1; }\r
+.cm-s-erlang-dark span.cm-bracket    { color: #ff9d00; }\r
+.cm-s-erlang-dark span.cm-builtin    { color: #eaa; }\r
+.cm-s-erlang-dark span.cm-comment    { color: #77f; }\r
+.cm-s-erlang-dark span.cm-def        { color: #e7a; }\r
+.cm-s-erlang-dark span.cm-keyword    { color: #ffee80; }\r
+.cm-s-erlang-dark span.cm-meta       { color: #50fefe; }\r
+.cm-s-erlang-dark span.cm-number     { color: #ffd0d0; }\r
+.cm-s-erlang-dark span.cm-operator   { color: #d55; }\r
+.cm-s-erlang-dark span.cm-property   { color: #ccc; }\r
+.cm-s-erlang-dark span.cm-qualifier  { color: #ccc; }\r
+.cm-s-erlang-dark span.cm-special    { color: #ffbbbb; }\r
+.cm-s-erlang-dark span.cm-string     { color: #3ad900; }\r
+.cm-s-erlang-dark span.cm-string-2   { color: #ccc; }\r
+.cm-s-erlang-dark span.cm-tag        { color: #9effff; }\r
+.cm-s-erlang-dark span.cm-variable   { color: #50fe50; }\r
+.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; }\r
+.cm-s-erlang-dark span.cm-variable-3, .cm-s-erlang-dark span.cm-type { color: #ccc; }\r
+.cm-s-erlang-dark span.cm-error      { color: #9d1e15; }\r
+\r
+.cm-s-erlang-dark .CodeMirror-activeline-background { background: #013461; }\r
+.cm-s-erlang-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/hopscotch.css b/js/ckeditor/plugins/codemirror/theme/hopscotch.css
new file mode 100644 (file)
index 0000000..c40094d
--- /dev/null
@@ -0,0 +1,34 @@
+/*\r
+\r
+    Name:       Hopscotch\r
+    Author:     Jan T. Sott\r
+\r
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\r
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\r
+\r
+*/\r
+\r
+.cm-s-hopscotch.CodeMirror {background: #322931; color: #d5d3d5;}\r
+.cm-s-hopscotch div.CodeMirror-selected {background: #433b42 !important;}\r
+.cm-s-hopscotch .CodeMirror-gutters {background: #322931; border-right: 0px;}\r
+.cm-s-hopscotch .CodeMirror-linenumber {color: #797379;}\r
+.cm-s-hopscotch .CodeMirror-cursor {border-left: 1px solid #989498 !important;}\r
+\r
+.cm-s-hopscotch span.cm-comment {color: #b33508;}\r
+.cm-s-hopscotch span.cm-atom {color: #c85e7c;}\r
+.cm-s-hopscotch span.cm-number {color: #c85e7c;}\r
+\r
+.cm-s-hopscotch span.cm-property, .cm-s-hopscotch span.cm-attribute {color: #8fc13e;}\r
+.cm-s-hopscotch span.cm-keyword {color: #dd464c;}\r
+.cm-s-hopscotch span.cm-string {color: #fdcc59;}\r
+\r
+.cm-s-hopscotch span.cm-variable {color: #8fc13e;}\r
+.cm-s-hopscotch span.cm-variable-2 {color: #1290bf;}\r
+.cm-s-hopscotch span.cm-def {color: #fd8b19;}\r
+.cm-s-hopscotch span.cm-error {background: #dd464c; color: #989498;}\r
+.cm-s-hopscotch span.cm-bracket {color: #d5d3d5;}\r
+.cm-s-hopscotch span.cm-tag {color: #dd464c;}\r
+.cm-s-hopscotch span.cm-link {color: #c85e7c;}\r
+\r
+.cm-s-hopscotch .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\r
+.cm-s-hopscotch .CodeMirror-activeline-background { background: #302020; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/icecoder.css b/js/ckeditor/plugins/codemirror/theme/icecoder.css
new file mode 100644 (file)
index 0000000..3056733
--- /dev/null
@@ -0,0 +1,43 @@
+/*\r
+ICEcoder default theme by Matt Pass, used in code editor available at https://icecoder.net\r
+*/\r
+\r
+.cm-s-icecoder { color: #666; background: #1d1d1b; }\r
+\r
+.cm-s-icecoder span.cm-keyword { color: #eee; font-weight:bold; }  /* off-white 1 */\r
+.cm-s-icecoder span.cm-atom { color: #e1c76e; }                    /* yellow */\r
+.cm-s-icecoder span.cm-number { color: #6cb5d9; }                  /* blue */\r
+.cm-s-icecoder span.cm-def { color: #b9ca4a; }                     /* green */\r
+\r
+.cm-s-icecoder span.cm-variable { color: #6cb5d9; }                /* blue */\r
+.cm-s-icecoder span.cm-variable-2 { color: #cc1e5c; }              /* pink */\r
+.cm-s-icecoder span.cm-variable-3, .cm-s-icecoder span.cm-type { color: #f9602c; } /* orange */\r
+\r
+.cm-s-icecoder span.cm-property { color: #eee; }                   /* off-white 1 */\r
+.cm-s-icecoder span.cm-operator { color: #9179bb; }                /* purple */\r
+.cm-s-icecoder span.cm-comment { color: #97a3aa; }                 /* grey-blue */\r
+\r
+.cm-s-icecoder span.cm-string { color: #b9ca4a; }                  /* green */\r
+.cm-s-icecoder span.cm-string-2 { color: #6cb5d9; }                /* blue */\r
+\r
+.cm-s-icecoder span.cm-meta { color: #555; }                       /* grey */\r
+\r
+.cm-s-icecoder span.cm-qualifier { color: #555; }                  /* grey */\r
+.cm-s-icecoder span.cm-builtin { color: #214e7b; }                 /* bright blue */\r
+.cm-s-icecoder span.cm-bracket { color: #cc7; }                    /* grey-yellow */\r
+\r
+.cm-s-icecoder span.cm-tag { color: #e8e8e8; }                     /* off-white 2 */\r
+.cm-s-icecoder span.cm-attribute { color: #099; }                  /* teal */\r
+\r
+.cm-s-icecoder span.cm-header { color: #6a0d6a; }                  /* purple-pink */\r
+.cm-s-icecoder span.cm-quote { color: #186718; }                   /* dark green */\r
+.cm-s-icecoder span.cm-hr { color: #888; }                         /* mid-grey */\r
+.cm-s-icecoder span.cm-link { color: #e1c76e; }                    /* yellow */\r
+.cm-s-icecoder span.cm-error { color: #d00; }                      /* red */\r
+\r
+.cm-s-icecoder .CodeMirror-cursor { border-left: 1px solid white; }\r
+.cm-s-icecoder div.CodeMirror-selected { color: #fff; background: #037; }\r
+.cm-s-icecoder .CodeMirror-gutters { background: #1d1d1b; min-width: 41px; border-right: 0; }\r
+.cm-s-icecoder .CodeMirror-linenumber { color: #555; cursor: default; }\r
+.cm-s-icecoder .CodeMirror-matchingbracket { color: #fff !important; background: #555 !important; }\r
+.cm-s-icecoder .CodeMirror-activeline-background { background: #000; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/isotope.css b/js/ckeditor/plugins/codemirror/theme/isotope.css
new file mode 100644 (file)
index 0000000..a9642ac
--- /dev/null
@@ -0,0 +1,34 @@
+/*\r
+\r
+    Name:       Isotope\r
+    Author:     David Desandro / Jan T. Sott\r
+\r
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\r
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\r
+\r
+*/\r
+\r
+.cm-s-isotope.CodeMirror {background: #000000; color: #e0e0e0;}\r
+.cm-s-isotope div.CodeMirror-selected {background: #404040 !important;}\r
+.cm-s-isotope .CodeMirror-gutters {background: #000000; border-right: 0px;}\r
+.cm-s-isotope .CodeMirror-linenumber {color: #808080;}\r
+.cm-s-isotope .CodeMirror-cursor {border-left: 1px solid #c0c0c0 !important;}\r
+\r
+.cm-s-isotope span.cm-comment {color: #3300ff;}\r
+.cm-s-isotope span.cm-atom {color: #cc00ff;}\r
+.cm-s-isotope span.cm-number {color: #cc00ff;}\r
+\r
+.cm-s-isotope span.cm-property, .cm-s-isotope span.cm-attribute {color: #33ff00;}\r
+.cm-s-isotope span.cm-keyword {color: #ff0000;}\r
+.cm-s-isotope span.cm-string {color: #ff0099;}\r
+\r
+.cm-s-isotope span.cm-variable {color: #33ff00;}\r
+.cm-s-isotope span.cm-variable-2 {color: #0066ff;}\r
+.cm-s-isotope span.cm-def {color: #ff9900;}\r
+.cm-s-isotope span.cm-error {background: #ff0000; color: #c0c0c0;}\r
+.cm-s-isotope span.cm-bracket {color: #e0e0e0;}\r
+.cm-s-isotope span.cm-tag {color: #ff0000;}\r
+.cm-s-isotope span.cm-link {color: #cc00ff;}\r
+\r
+.cm-s-isotope .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\r
+.cm-s-isotope .CodeMirror-activeline-background { background: #202020; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/lesser-dark.css b/js/ckeditor/plugins/codemirror/theme/lesser-dark.css
new file mode 100644 (file)
index 0000000..303e232
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+http://lesscss.org/ dark theme\r
+Ported to CodeMirror by Peter Kroon\r
+*/\r
+.cm-s-lesser-dark {\r
+  line-height: 1.3em;\r
+}\r
+.cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }\r
+.cm-s-lesser-dark div.CodeMirror-selected { background: #45443B; } /* 33322B*/\r
+.cm-s-lesser-dark .CodeMirror-line::selection, .cm-s-lesser-dark .CodeMirror-line > span::selection, .cm-s-lesser-dark .CodeMirror-line > span > span::selection { background: rgba(69, 68, 59, .99); }\r
+.cm-s-lesser-dark .CodeMirror-line::-moz-selection, .cm-s-lesser-dark .CodeMirror-line > span::-moz-selection, .cm-s-lesser-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(69, 68, 59, .99); }\r
+.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white; }\r
+.cm-s-lesser-dark pre { padding: 0 8px; }/*editable code holder*/\r
+\r
+.cm-s-lesser-dark.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/\r
+\r
+.cm-s-lesser-dark .CodeMirror-gutters { background: #262626; border-right:1px solid #aaa; }\r
+.cm-s-lesser-dark .CodeMirror-guttermarker { color: #599eff; }\r
+.cm-s-lesser-dark .CodeMirror-guttermarker-subtle { color: #777; }\r
+.cm-s-lesser-dark .CodeMirror-linenumber { color: #777; }\r
+\r
+.cm-s-lesser-dark span.cm-header { color: #a0a; }\r
+.cm-s-lesser-dark span.cm-quote { color: #090; }\r
+.cm-s-lesser-dark span.cm-keyword { color: #599eff; }\r
+.cm-s-lesser-dark span.cm-atom { color: #C2B470; }\r
+.cm-s-lesser-dark span.cm-number { color: #B35E4D; }\r
+.cm-s-lesser-dark span.cm-def { color: white; }\r
+.cm-s-lesser-dark span.cm-variable { color:#D9BF8C; }\r
+.cm-s-lesser-dark span.cm-variable-2 { color: #669199; }\r
+.cm-s-lesser-dark span.cm-variable-3, .cm-s-lesser-dark span.cm-type { color: white; }\r
+.cm-s-lesser-dark span.cm-property { color: #92A75C; }\r
+.cm-s-lesser-dark span.cm-operator { color: #92A75C; }\r
+.cm-s-lesser-dark span.cm-comment { color: #666; }\r
+.cm-s-lesser-dark span.cm-string { color: #BCD279; }\r
+.cm-s-lesser-dark span.cm-string-2 { color: #f50; }\r
+.cm-s-lesser-dark span.cm-meta { color: #738C73; }\r
+.cm-s-lesser-dark span.cm-qualifier { color: #555; }\r
+.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; }\r
+.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; }\r
+.cm-s-lesser-dark span.cm-tag { color: #669199; }\r
+.cm-s-lesser-dark span.cm-attribute { color: #00c; }\r
+.cm-s-lesser-dark span.cm-hr { color: #999; }\r
+.cm-s-lesser-dark span.cm-link { color: #00c; }\r
+.cm-s-lesser-dark span.cm-error { color: #9d1e15; }\r
+\r
+.cm-s-lesser-dark .CodeMirror-activeline-background { background: #3C3A3A; }\r
+.cm-s-lesser-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/liquibyte.css b/js/ckeditor/plugins/codemirror/theme/liquibyte.css
new file mode 100644 (file)
index 0000000..fa164f6
--- /dev/null
@@ -0,0 +1,95 @@
+.cm-s-liquibyte.CodeMirror {\r
+       background-color: #000;\r
+       color: #fff;\r
+       line-height: 1.2em;\r
+       font-size: 1em;\r
+}\r
+.cm-s-liquibyte .CodeMirror-focused .cm-matchhighlight {\r
+       text-decoration: underline;\r
+       text-decoration-color: #0f0;\r
+       text-decoration-style: wavy;\r
+}\r
+.cm-s-liquibyte .cm-trailingspace {\r
+       text-decoration: line-through;\r
+       text-decoration-color: #f00;\r
+       text-decoration-style: dotted;\r
+}\r
+.cm-s-liquibyte .cm-tab {\r
+       text-decoration: line-through;\r
+       text-decoration-color: #404040;\r
+       text-decoration-style: dotted;\r
+}\r
+.cm-s-liquibyte .CodeMirror-gutters { background-color: #262626; border-right: 1px solid #505050; padding-right: 0.8em; }\r
+.cm-s-liquibyte .CodeMirror-gutter-elt div { font-size: 1.2em; }\r
+.cm-s-liquibyte .CodeMirror-guttermarker {  }\r
+.cm-s-liquibyte .CodeMirror-guttermarker-subtle {  }\r
+.cm-s-liquibyte .CodeMirror-linenumber { color: #606060; padding-left: 0; }\r
+.cm-s-liquibyte .CodeMirror-cursor { border-left: 1px solid #eee; }\r
+\r
+.cm-s-liquibyte span.cm-comment     { color: #008000; }\r
+.cm-s-liquibyte span.cm-def         { color: #ffaf40; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-keyword     { color: #c080ff; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-builtin     { color: #ffaf40; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-variable    { color: #5967ff; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-string      { color: #ff8000; }\r
+.cm-s-liquibyte span.cm-number      { color: #0f0; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-atom        { color: #bf3030; font-weight: bold; }\r
+\r
+.cm-s-liquibyte span.cm-variable-2  { color: #007f7f; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-variable-3, .cm-s-liquibyte span.cm-type { color: #c080ff; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-property    { color: #999; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-operator    { color: #fff; }\r
+\r
+.cm-s-liquibyte span.cm-meta        { color: #0f0; }\r
+.cm-s-liquibyte span.cm-qualifier   { color: #fff700; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-bracket     { color: #cc7; }\r
+.cm-s-liquibyte span.cm-tag         { color: #ff0; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-attribute   { color: #c080ff; font-weight: bold; }\r
+.cm-s-liquibyte span.cm-error       { color: #f00; }\r
+\r
+.cm-s-liquibyte div.CodeMirror-selected { background-color: rgba(255, 0, 0, 0.25); }\r
+\r
+.cm-s-liquibyte span.cm-compilation { background-color: rgba(255, 255, 255, 0.12); }\r
+\r
+.cm-s-liquibyte .CodeMirror-activeline-background { background-color: rgba(0, 255, 0, 0.15); }\r
+\r
+/* Default styles for common addons */\r
+.cm-s-liquibyte .CodeMirror span.CodeMirror-matchingbracket { color: #0f0; font-weight: bold; }\r
+.cm-s-liquibyte .CodeMirror span.CodeMirror-nonmatchingbracket { color: #f00; font-weight: bold; }\r
+.CodeMirror-matchingtag { background-color: rgba(150, 255, 0, .3); }\r
+/* Scrollbars */\r
+/* Simple */\r
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div:hover, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div:hover {\r
+       background-color: rgba(80, 80, 80, .7);\r
+}\r
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div {\r
+       background-color: rgba(80, 80, 80, .3);\r
+       border: 1px solid #404040;\r
+       border-radius: 5px;\r
+}\r
+.cm-s-liquibyte div.CodeMirror-simplescroll-vertical div {\r
+       border-top: 1px solid #404040;\r
+       border-bottom: 1px solid #404040;\r
+}\r
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div {\r
+       border-left: 1px solid #404040;\r
+       border-right: 1px solid #404040;\r
+}\r
+.cm-s-liquibyte div.CodeMirror-simplescroll-vertical {\r
+       background-color: #262626;\r
+}\r
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal {\r
+       background-color: #262626;\r
+       border-top: 1px solid #404040;\r
+}\r
+/* Overlay */\r
+.cm-s-liquibyte div.CodeMirror-overlayscroll-horizontal div, div.CodeMirror-overlayscroll-vertical div {\r
+       background-color: #404040;\r
+       border-radius: 5px;\r
+}\r
+.cm-s-liquibyte div.CodeMirror-overlayscroll-vertical div {\r
+       border: 1px solid #404040;\r
+}\r
+.cm-s-liquibyte div.CodeMirror-overlayscroll-horizontal div {\r
+       border: 1px solid #404040;\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/material.css b/js/ckeditor/plugins/codemirror/theme/material.css
new file mode 100644 (file)
index 0000000..634a01a
--- /dev/null
@@ -0,0 +1,53 @@
+/*\r
+\r
+    Name:       material\r
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)\r
+\r
+    Original material color scheme by Mattia Astorino (https://github.com/equinusocio/material-theme)\r
+\r
+*/\r
+\r
+.cm-s-material.CodeMirror {\r
+  background-color: #263238;\r
+  color: rgba(233, 237, 237, 1);\r
+}\r
+.cm-s-material .CodeMirror-gutters {\r
+  background: #263238;\r
+  color: rgb(83,127,126);\r
+  border: none;\r
+}\r
+.cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber { color: rgb(83,127,126); }\r
+.cm-s-material .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }\r
+.cm-s-material div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }\r
+.cm-s-material.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line > span::selection, .cm-s-material .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }\r
+\r
+.cm-s-material .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0); }\r
+.cm-s-material .cm-keyword { color: rgba(199, 146, 234, 1); }\r
+.cm-s-material .cm-operator { color: rgba(233, 237, 237, 1); }\r
+.cm-s-material .cm-variable-2 { color: #80CBC4; }\r
+.cm-s-material .cm-variable-3, .cm-s-material .cm-type { color: #82B1FF; }\r
+.cm-s-material .cm-builtin { color: #DECB6B; }\r
+.cm-s-material .cm-atom { color: #F77669; }\r
+.cm-s-material .cm-number { color: #F77669; }\r
+.cm-s-material .cm-def { color: rgba(233, 237, 237, 1); }\r
+.cm-s-material .cm-string { color: #C3E88D; }\r
+.cm-s-material .cm-string-2 { color: #80CBC4; }\r
+.cm-s-material .cm-comment { color: #546E7A; }\r
+.cm-s-material .cm-variable { color: #82B1FF; }\r
+.cm-s-material .cm-tag { color: #80CBC4; }\r
+.cm-s-material .cm-meta { color: #80CBC4; }\r
+.cm-s-material .cm-attribute { color: #FFCB6B; }\r
+.cm-s-material .cm-property { color: #80CBAE; }\r
+.cm-s-material .cm-qualifier { color: #DECB6B; }\r
+.cm-s-material .cm-variable-3, .cm-s-material .cm-type { color: #DECB6B; }\r
+.cm-s-material .cm-tag { color: rgba(255, 83, 112, 1); }\r
+.cm-s-material .cm-error {\r
+  color: rgba(255, 255, 255, 1.0);\r
+  background-color: #EC5F67;\r
+}\r
+.cm-s-material .CodeMirror-matchingbracket {\r
+  text-decoration: underline;\r
+  color: white !important;\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/mbo.css b/js/ckeditor/plugins/codemirror/theme/mbo.css
new file mode 100644 (file)
index 0000000..a64c0fd
--- /dev/null
@@ -0,0 +1,37 @@
+/****************************************************************/\r
+/*   Based on mbonaci's Brackets mbo theme                      */\r
+/*   https://github.com/mbonaci/global/blob/master/Mbo.tmTheme  */\r
+/*   Create your own: http://tmtheme-editor.herokuapp.com       */\r
+/****************************************************************/\r
+\r
+.cm-s-mbo.CodeMirror { background: #2c2c2c; color: #ffffec; }\r
+.cm-s-mbo div.CodeMirror-selected { background: #716C62; }\r
+.cm-s-mbo .CodeMirror-line::selection, .cm-s-mbo .CodeMirror-line > span::selection, .cm-s-mbo .CodeMirror-line > span > span::selection { background: rgba(113, 108, 98, .99); }\r
+.cm-s-mbo .CodeMirror-line::-moz-selection, .cm-s-mbo .CodeMirror-line > span::-moz-selection, .cm-s-mbo .CodeMirror-line > span > span::-moz-selection { background: rgba(113, 108, 98, .99); }\r
+.cm-s-mbo .CodeMirror-gutters { background: #4e4e4e; border-right: 0px; }\r
+.cm-s-mbo .CodeMirror-guttermarker { color: white; }\r
+.cm-s-mbo .CodeMirror-guttermarker-subtle { color: grey; }\r
+.cm-s-mbo .CodeMirror-linenumber { color: #dadada; }\r
+.cm-s-mbo .CodeMirror-cursor { border-left: 1px solid #ffffec; }\r
+\r
+.cm-s-mbo span.cm-comment { color: #95958a; }\r
+.cm-s-mbo span.cm-atom { color: #00a8c6; }\r
+.cm-s-mbo span.cm-number { color: #00a8c6; }\r
+\r
+.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute { color: #9ddfe9; }\r
+.cm-s-mbo span.cm-keyword { color: #ffb928; }\r
+.cm-s-mbo span.cm-string { color: #ffcf6c; }\r
+.cm-s-mbo span.cm-string.cm-property { color: #ffffec; }\r
+\r
+.cm-s-mbo span.cm-variable { color: #ffffec; }\r
+.cm-s-mbo span.cm-variable-2 { color: #00a8c6; }\r
+.cm-s-mbo span.cm-def { color: #ffffec; }\r
+.cm-s-mbo span.cm-bracket { color: #fffffc; font-weight: bold; }\r
+.cm-s-mbo span.cm-tag { color: #9ddfe9; }\r
+.cm-s-mbo span.cm-link { color: #f54b07; }\r
+.cm-s-mbo span.cm-error { border-bottom: #636363; color: #ffffec; }\r
+.cm-s-mbo span.cm-qualifier { color: #ffffec; }\r
+\r
+.cm-s-mbo .CodeMirror-activeline-background { background: #494b41; }\r
+.cm-s-mbo .CodeMirror-matchingbracket { color: #ffb928 !important; }\r
+.cm-s-mbo .CodeMirror-matchingtag { background: rgba(255, 255, 255, .37); }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/mdn-like.css b/js/ckeditor/plugins/codemirror/theme/mdn-like.css
new file mode 100644 (file)
index 0000000..c8c6de0
--- /dev/null
@@ -0,0 +1,46 @@
+/*\r
+  MDN-LIKE Theme - Mozilla\r
+  Ported to CodeMirror by Peter Kroon <plakroon@gmail.com>\r
+  Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues\r
+  GitHub: @peterkroon\r
+\r
+  The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation\r
+\r
+*/\r
+.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; }\r
+.cm-s-mdn-like div.CodeMirror-selected { background: #cfc; }\r
+.cm-s-mdn-like .CodeMirror-line::selection, .cm-s-mdn-like .CodeMirror-line > span::selection, .cm-s-mdn-like .CodeMirror-line > span > span::selection { background: #cfc; }\r
+.cm-s-mdn-like .CodeMirror-line::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span > span::-moz-selection { background: #cfc; }\r
+\r
+.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; }\r
+.cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; padding-left: 8px; }\r
+.cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; }\r
+\r
+.cm-s-mdn-like .cm-keyword { color: #6262FF; }\r
+.cm-s-mdn-like .cm-atom { color: #F90; }\r
+.cm-s-mdn-like .cm-number { color:  #ca7841; }\r
+.cm-s-mdn-like .cm-def { color: #8DA6CE; }\r
+.cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; }\r
+.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def, .cm-s-mdn-like span.cm-type { color: #07a; }\r
+\r
+.cm-s-mdn-like .cm-variable { color: #07a; }\r
+.cm-s-mdn-like .cm-property { color: #905; }\r
+.cm-s-mdn-like .cm-qualifier { color: #690; }\r
+\r
+.cm-s-mdn-like .cm-operator { color: #cda869; }\r
+.cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; }\r
+.cm-s-mdn-like .cm-string { color:#07a; font-style:italic; }\r
+.cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/\r
+.cm-s-mdn-like .cm-meta { color: #000; } /*?*/\r
+.cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/\r
+.cm-s-mdn-like .cm-tag { color: #997643; }\r
+.cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/\r
+.cm-s-mdn-like .cm-header { color: #FF6400; }\r
+.cm-s-mdn-like .cm-hr { color: #AEAEAE; }\r
+.cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; }\r
+.cm-s-mdn-like .cm-error { border-bottom: 1px solid red; }\r
+\r
+div.cm-s-mdn-like .CodeMirror-activeline-background { background: #efefff; }\r
+div.cm-s-mdn-like span.CodeMirror-matchingbracket { outline:1px solid grey; color: inherit; }\r
+\r
+.cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/midnight.css b/js/ckeditor/plugins/codemirror/theme/midnight.css
new file mode 100644 (file)
index 0000000..d9bdc2c
--- /dev/null
@@ -0,0 +1,43 @@
+/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */\r
+\r
+/*<!--match-->*/\r
+.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949; }\r
+.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; }\r
+\r
+/*<!--activeline-->*/\r
+.cm-s-midnight .CodeMirror-activeline-background { background: #253540; }\r
+\r
+.cm-s-midnight.CodeMirror {\r
+    background: #0F192A;\r
+    color: #D1EDFF;\r
+}\r
+\r
+.cm-s-midnight div.CodeMirror-selected { background: #314D67; }\r
+.cm-s-midnight .CodeMirror-line::selection, .cm-s-midnight .CodeMirror-line > span::selection, .cm-s-midnight .CodeMirror-line > span > span::selection { background: rgba(49, 77, 103, .99); }\r
+.cm-s-midnight .CodeMirror-line::-moz-selection, .cm-s-midnight .CodeMirror-line > span::-moz-selection, .cm-s-midnight .CodeMirror-line > span > span::-moz-selection { background: rgba(49, 77, 103, .99); }\r
+.cm-s-midnight .CodeMirror-gutters { background: #0F192A; border-right: 1px solid; }\r
+.cm-s-midnight .CodeMirror-guttermarker { color: white; }\r
+.cm-s-midnight .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\r
+.cm-s-midnight .CodeMirror-linenumber { color: #D0D0D0; }\r
+.cm-s-midnight .CodeMirror-cursor { border-left: 1px solid #F8F8F0; }\r
+\r
+.cm-s-midnight span.cm-comment { color: #428BDD; }\r
+.cm-s-midnight span.cm-atom { color: #AE81FF; }\r
+.cm-s-midnight span.cm-number { color: #D1EDFF; }\r
+\r
+.cm-s-midnight span.cm-property, .cm-s-midnight span.cm-attribute { color: #A6E22E; }\r
+.cm-s-midnight span.cm-keyword { color: #E83737; }\r
+.cm-s-midnight span.cm-string { color: #1DC116; }\r
+\r
+.cm-s-midnight span.cm-variable { color: #FFAA3E; }\r
+.cm-s-midnight span.cm-variable-2 { color: #FFAA3E; }\r
+.cm-s-midnight span.cm-def { color: #4DD; }\r
+.cm-s-midnight span.cm-bracket { color: #D1EDFF; }\r
+.cm-s-midnight span.cm-tag { color: #449; }\r
+.cm-s-midnight span.cm-link { color: #AE81FF; }\r
+.cm-s-midnight span.cm-error { background: #F92672; color: #F8F8F0; }\r
+\r
+.cm-s-midnight .CodeMirror-matchingbracket {\r
+  text-decoration: underline;\r
+  color: white !important;\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/monokai.css b/js/ckeditor/plugins/codemirror/theme/monokai.css
new file mode 100644 (file)
index 0000000..69be556
--- /dev/null
@@ -0,0 +1,36 @@
+/* Based on Sublime Text's Monokai theme */\r
+\r
+.cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; }\r
+.cm-s-monokai div.CodeMirror-selected { background: #49483E; }\r
+.cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); }\r
+.cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); }\r
+.cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; }\r
+.cm-s-monokai .CodeMirror-guttermarker { color: white; }\r
+.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\r
+.cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; }\r
+.cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }\r
+\r
+.cm-s-monokai span.cm-comment { color: #75715e; }\r
+.cm-s-monokai span.cm-atom { color: #ae81ff; }\r
+.cm-s-monokai span.cm-number { color: #ae81ff; }\r
+\r
+.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; }\r
+.cm-s-monokai span.cm-keyword { color: #f92672; }\r
+.cm-s-monokai span.cm-builtin { color: #66d9ef; }\r
+.cm-s-monokai span.cm-string { color: #e6db74; }\r
+\r
+.cm-s-monokai span.cm-variable { color: #f8f8f2; }\r
+.cm-s-monokai span.cm-variable-2 { color: #9effff; }\r
+.cm-s-monokai span.cm-variable-3, .cm-s-monokai span.cm-type { color: #66d9ef; }\r
+.cm-s-monokai span.cm-def { color: #fd971f; }\r
+.cm-s-monokai span.cm-bracket { color: #f8f8f2; }\r
+.cm-s-monokai span.cm-tag { color: #f92672; }\r
+.cm-s-monokai span.cm-header { color: #ae81ff; }\r
+.cm-s-monokai span.cm-link { color: #ae81ff; }\r
+.cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; }\r
+\r
+.cm-s-monokai .CodeMirror-activeline-background { background: #373831; }\r
+.cm-s-monokai .CodeMirror-matchingbracket {\r
+  text-decoration: underline;\r
+  color: white !important;\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/neat.css b/js/ckeditor/plugins/codemirror/theme/neat.css
new file mode 100644 (file)
index 0000000..d454fbb
--- /dev/null
@@ -0,0 +1,12 @@
+.cm-s-neat span.cm-comment { color: #a86; }\r
+.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; }\r
+.cm-s-neat span.cm-string { color: #a22; }\r
+.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }\r
+.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }\r
+.cm-s-neat span.cm-variable { color: black; }\r
+.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }\r
+.cm-s-neat span.cm-meta { color: #555; }\r
+.cm-s-neat span.cm-link { color: #3a3; }\r
+\r
+.cm-s-neat .CodeMirror-activeline-background { background: #e8f2ff; }\r
+.cm-s-neat .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/neo.css b/js/ckeditor/plugins/codemirror/theme/neo.css
new file mode 100644 (file)
index 0000000..42a0a49
--- /dev/null
@@ -0,0 +1,43 @@
+/* neo theme for codemirror */\r
+\r
+/* Color scheme */\r
+\r
+.cm-s-neo.CodeMirror {\r
+  background-color:#ffffff;\r
+  color:#2e383c;\r
+  line-height:1.4375;\r
+}\r
+.cm-s-neo .cm-comment { color:#75787b; }\r
+.cm-s-neo .cm-keyword, .cm-s-neo .cm-property { color:#1d75b3; }\r
+.cm-s-neo .cm-atom,.cm-s-neo .cm-number { color:#75438a; }\r
+.cm-s-neo .cm-node,.cm-s-neo .cm-tag { color:#9c3328; }\r
+.cm-s-neo .cm-string { color:#b35e14; }\r
+.cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier { color:#047d65; }\r
+\r
+\r
+/* Editor styling */\r
+\r
+.cm-s-neo pre {\r
+  padding:0;\r
+}\r
+\r
+.cm-s-neo .CodeMirror-gutters {\r
+  border:none;\r
+  border-right:10px solid transparent;\r
+  background-color:transparent;\r
+}\r
+\r
+.cm-s-neo .CodeMirror-linenumber {\r
+  padding:0;\r
+  color:#e0e2e5;\r
+}\r
+\r
+.cm-s-neo .CodeMirror-guttermarker { color: #1d75b3; }\r
+.cm-s-neo .CodeMirror-guttermarker-subtle { color: #e0e2e5; }\r
+\r
+.cm-s-neo .CodeMirror-cursor {\r
+  width: auto;\r
+  border: 0;\r
+  background: rgba(155,157,162,0.37);\r
+  z-index: 1;\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/night.css b/js/ckeditor/plugins/codemirror/theme/night.css
new file mode 100644 (file)
index 0000000..07925c5
--- /dev/null
@@ -0,0 +1,27 @@
+/* Loosely based on the Midnight Textmate theme */\r
+\r
+.cm-s-night.CodeMirror { background: #0a001f; color: #f8f8f8; }\r
+.cm-s-night div.CodeMirror-selected { background: #447; }\r
+.cm-s-night .CodeMirror-line::selection, .cm-s-night .CodeMirror-line > span::selection, .cm-s-night .CodeMirror-line > span > span::selection { background: rgba(68, 68, 119, .99); }\r
+.cm-s-night .CodeMirror-line::-moz-selection, .cm-s-night .CodeMirror-line > span::-moz-selection, .cm-s-night .CodeMirror-line > span > span::-moz-selection { background: rgba(68, 68, 119, .99); }\r
+.cm-s-night .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }\r
+.cm-s-night .CodeMirror-guttermarker { color: white; }\r
+.cm-s-night .CodeMirror-guttermarker-subtle { color: #bbb; }\r
+.cm-s-night .CodeMirror-linenumber { color: #f8f8f8; }\r
+.cm-s-night .CodeMirror-cursor { border-left: 1px solid white; }\r
+\r
+.cm-s-night span.cm-comment { color: #8900d1; }\r
+.cm-s-night span.cm-atom { color: #845dc4; }\r
+.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }\r
+.cm-s-night span.cm-keyword { color: #599eff; }\r
+.cm-s-night span.cm-string { color: #37f14a; }\r
+.cm-s-night span.cm-meta { color: #7678e2; }\r
+.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }\r
+.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def, .cm-s-night span.cm-type { color: white; }\r
+.cm-s-night span.cm-bracket { color: #8da6ce; }\r
+.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }\r
+.cm-s-night span.cm-link { color: #845dc4; }\r
+.cm-s-night span.cm-error { color: #9d1e15; }\r
+\r
+.cm-s-night .CodeMirror-activeline-background { background: #1C005A; }\r
+.cm-s-night .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/panda-syntax.css b/js/ckeditor/plugins/codemirror/theme/panda-syntax.css
new file mode 100644 (file)
index 0000000..e9da8ca
--- /dev/null
@@ -0,0 +1,85 @@
+/*\r
+       Name:       Panda Syntax\r
+       Author:     Siamak Mokhtari (http://github.com/siamak/)\r
+       CodeMirror template by Siamak Mokhtari (https://github.com/siamak/atom-panda-syntax)\r
+*/\r
+.cm-s-panda-syntax {\r
+       background: #292A2B;\r
+       color: #E6E6E6;\r
+       line-height: 1.5;\r
+       font-family: 'Operator Mono', 'Source Sans Pro', Menlo, Monaco, Consolas, Courier New, monospace;\r
+}\r
+.cm-s-panda-syntax .CodeMirror-cursor { border-color: #ff2c6d; }\r
+.cm-s-panda-syntax .CodeMirror-activeline-background {\r
+       background: rgba(99, 123, 156, 0.1);\r
+}\r
+.cm-s-panda-syntax .CodeMirror-selected {\r
+       background: #FFF;\r
+}\r
+.cm-s-panda-syntax .cm-comment {\r
+       font-style: italic;\r
+       color: #676B79;\r
+}\r
+.cm-s-panda-syntax .cm-operator {\r
+       color: #f3f3f3;\r
+}\r
+.cm-s-panda-syntax .cm-string {\r
+       color: #19F9D8;\r
+}\r
+.cm-s-panda-syntax .cm-string-2 {\r
+    color: #FFB86C;\r
+}\r
+\r
+.cm-s-panda-syntax .cm-tag {\r
+       color: #ff2c6d;\r
+}\r
+.cm-s-panda-syntax .cm-meta {\r
+       color: #b084eb;\r
+}\r
+\r
+.cm-s-panda-syntax .cm-number {\r
+       color: #FFB86C;\r
+}\r
+.cm-s-panda-syntax .cm-atom {\r
+       color: #ff2c6d;\r
+}\r
+.cm-s-panda-syntax .cm-keyword {\r
+       color: #FF75B5;\r
+}\r
+.cm-s-panda-syntax .cm-variable {\r
+       color: #ffb86c;\r
+}\r
+.cm-s-panda-syntax .cm-variable-2 {\r
+       color: #ff9ac1;\r
+}\r
+.cm-s-panda-syntax .cm-variable-3, .cm-s-panda-syntax .cm-type {\r
+       color: #ff9ac1;\r
+}\r
+\r
+.cm-s-panda-syntax .cm-def {\r
+       color: #e6e6e6;\r
+}\r
+.cm-s-panda-syntax .cm-property {\r
+       color: #f3f3f3;\r
+}\r
+.cm-s-panda-syntax .cm-unit {\r
+    color: #ffb86c;\r
+}\r
+\r
+.cm-s-panda-syntax .cm-attribute {\r
+    color: #ffb86c;\r
+}\r
+\r
+.cm-s-panda-syntax .CodeMirror-matchingbracket {\r
+    border-bottom: 1px dotted #19F9D8;\r
+    padding-bottom: 2px;\r
+    color: #e6e6e6;\r
+}\r
+.cm-s-panda-syntax .CodeMirror-gutters {\r
+    background: #292a2b;\r
+    border-right-color: rgba(255, 255, 255, 0.1);\r
+}\r
+.cm-s-panda-syntax .CodeMirror-linenumber {\r
+    color: #e6e6e6;\r
+    opacity: 0.6;\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/paraiso-dark.css b/js/ckeditor/plugins/codemirror/theme/paraiso-dark.css
new file mode 100644 (file)
index 0000000..25eb926
--- /dev/null
@@ -0,0 +1,38 @@
+/*\r
+\r
+    Name:       Paraíso (Dark)\r
+    Author:     Jan T. Sott\r
+\r
+    Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)\r
+    Inspired by the art of Rubens LP (http://www.rubenslp.com.br)\r
+\r
+*/\r
+\r
+.cm-s-paraiso-dark.CodeMirror { background: #2f1e2e; color: #b9b6b0; }\r
+.cm-s-paraiso-dark div.CodeMirror-selected { background: #41323f; }\r
+.cm-s-paraiso-dark .CodeMirror-line::selection, .cm-s-paraiso-dark .CodeMirror-line > span::selection, .cm-s-paraiso-dark .CodeMirror-line > span > span::selection { background: rgba(65, 50, 63, .99); }\r
+.cm-s-paraiso-dark .CodeMirror-line::-moz-selection, .cm-s-paraiso-dark .CodeMirror-line > span::-moz-selection, .cm-s-paraiso-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(65, 50, 63, .99); }\r
+.cm-s-paraiso-dark .CodeMirror-gutters { background: #2f1e2e; border-right: 0px; }\r
+.cm-s-paraiso-dark .CodeMirror-guttermarker { color: #ef6155; }\r
+.cm-s-paraiso-dark .CodeMirror-guttermarker-subtle { color: #776e71; }\r
+.cm-s-paraiso-dark .CodeMirror-linenumber { color: #776e71; }\r
+.cm-s-paraiso-dark .CodeMirror-cursor { border-left: 1px solid #8d8687; }\r
+\r
+.cm-s-paraiso-dark span.cm-comment { color: #e96ba8; }\r
+.cm-s-paraiso-dark span.cm-atom { color: #815ba4; }\r
+.cm-s-paraiso-dark span.cm-number { color: #815ba4; }\r
+\r
+.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute { color: #48b685; }\r
+.cm-s-paraiso-dark span.cm-keyword { color: #ef6155; }\r
+.cm-s-paraiso-dark span.cm-string { color: #fec418; }\r
+\r
+.cm-s-paraiso-dark span.cm-variable { color: #48b685; }\r
+.cm-s-paraiso-dark span.cm-variable-2 { color: #06b6ef; }\r
+.cm-s-paraiso-dark span.cm-def { color: #f99b15; }\r
+.cm-s-paraiso-dark span.cm-bracket { color: #b9b6b0; }\r
+.cm-s-paraiso-dark span.cm-tag { color: #ef6155; }\r
+.cm-s-paraiso-dark span.cm-link { color: #815ba4; }\r
+.cm-s-paraiso-dark span.cm-error { background: #ef6155; color: #8d8687; }\r
+\r
+.cm-s-paraiso-dark .CodeMirror-activeline-background { background: #4D344A; }\r
+.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/paraiso-light.css b/js/ckeditor/plugins/codemirror/theme/paraiso-light.css
new file mode 100644 (file)
index 0000000..479792e
--- /dev/null
@@ -0,0 +1,38 @@
+/*\r
+\r
+    Name:       Paraíso (Light)\r
+    Author:     Jan T. Sott\r
+\r
+    Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)\r
+    Inspired by the art of Rubens LP (http://www.rubenslp.com.br)\r
+\r
+*/\r
+\r
+.cm-s-paraiso-light.CodeMirror { background: #e7e9db; color: #41323f; }\r
+.cm-s-paraiso-light div.CodeMirror-selected { background: #b9b6b0; }\r
+.cm-s-paraiso-light .CodeMirror-line::selection, .cm-s-paraiso-light .CodeMirror-line > span::selection, .cm-s-paraiso-light .CodeMirror-line > span > span::selection { background: #b9b6b0; }\r
+.cm-s-paraiso-light .CodeMirror-line::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span > span::-moz-selection { background: #b9b6b0; }\r
+.cm-s-paraiso-light .CodeMirror-gutters { background: #e7e9db; border-right: 0px; }\r
+.cm-s-paraiso-light .CodeMirror-guttermarker { color: black; }\r
+.cm-s-paraiso-light .CodeMirror-guttermarker-subtle { color: #8d8687; }\r
+.cm-s-paraiso-light .CodeMirror-linenumber { color: #8d8687; }\r
+.cm-s-paraiso-light .CodeMirror-cursor { border-left: 1px solid #776e71; }\r
+\r
+.cm-s-paraiso-light span.cm-comment { color: #e96ba8; }\r
+.cm-s-paraiso-light span.cm-atom { color: #815ba4; }\r
+.cm-s-paraiso-light span.cm-number { color: #815ba4; }\r
+\r
+.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute { color: #48b685; }\r
+.cm-s-paraiso-light span.cm-keyword { color: #ef6155; }\r
+.cm-s-paraiso-light span.cm-string { color: #fec418; }\r
+\r
+.cm-s-paraiso-light span.cm-variable { color: #48b685; }\r
+.cm-s-paraiso-light span.cm-variable-2 { color: #06b6ef; }\r
+.cm-s-paraiso-light span.cm-def { color: #f99b15; }\r
+.cm-s-paraiso-light span.cm-bracket { color: #41323f; }\r
+.cm-s-paraiso-light span.cm-tag { color: #ef6155; }\r
+.cm-s-paraiso-light span.cm-link { color: #815ba4; }\r
+.cm-s-paraiso-light span.cm-error { background: #ef6155; color: #776e71; }\r
+\r
+.cm-s-paraiso-light .CodeMirror-activeline-background { background: #CFD1C4; }\r
+.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/pastel-on-dark.css b/js/ckeditor/plugins/codemirror/theme/pastel-on-dark.css
new file mode 100644 (file)
index 0000000..9fcfea8
--- /dev/null
@@ -0,0 +1,52 @@
+/**\r
+ * Pastel On Dark theme ported from ACE editor\r
+ * @license MIT\r
+ * @copyright AtomicPages LLC 2014\r
+ * @author Dennis Thompson, AtomicPages LLC\r
+ * @version 1.1\r
+ * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme\r
+ */\r
+\r
+.cm-s-pastel-on-dark.CodeMirror {\r
+       background: #2c2827;\r
+       color: #8F938F;\r
+       line-height: 1.5;\r
+}\r
+.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2); }\r
+.cm-s-pastel-on-dark .CodeMirror-line::selection, .cm-s-pastel-on-dark .CodeMirror-line > span::selection, .cm-s-pastel-on-dark .CodeMirror-line > span > span::selection { background: rgba(221,240,255,0.2); }\r
+.cm-s-pastel-on-dark .CodeMirror-line::-moz-selection, .cm-s-pastel-on-dark .CodeMirror-line > span::-moz-selection, .cm-s-pastel-on-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(221,240,255,0.2); }\r
+\r
+.cm-s-pastel-on-dark .CodeMirror-gutters {\r
+       background: #34302f;\r
+       border-right: 0px;\r
+       padding: 0 3px;\r
+}\r
+.cm-s-pastel-on-dark .CodeMirror-guttermarker { color: white; }\r
+.cm-s-pastel-on-dark .CodeMirror-guttermarker-subtle { color: #8F938F; }\r
+.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; }\r
+.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7; }\r
+.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; }\r
+.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; }\r
+.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; }\r
+.cm-s-pastel-on-dark span.cm-property { color: #8F938F; }\r
+.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; }\r
+.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; }\r
+.cm-s-pastel-on-dark span.cm-string { color: #66A968; }\r
+.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; }\r
+.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; }\r
+.cm-s-pastel-on-dark span.cm-variable-3, .cm-s-pastel-on-dark span.cm-type { color: #DE8E30; }\r
+.cm-s-pastel-on-dark span.cm-def { color: #757aD8; }\r
+.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; }\r
+.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; }\r
+.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; }\r
+.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; }\r
+.cm-s-pastel-on-dark span.cm-error {\r
+       background: #757aD8;\r
+       color: #f8f8f0;\r
+}\r
+.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031); }\r
+.cm-s-pastel-on-dark .CodeMirror-matchingbracket {\r
+       border: 1px solid rgba(255,255,255,0.25);\r
+       color: #8F938F !important;\r
+       margin: -1px -1px 0 -1px;\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/railscasts.css b/js/ckeditor/plugins/codemirror/theme/railscasts.css
new file mode 100644 (file)
index 0000000..2336e7c
--- /dev/null
@@ -0,0 +1,34 @@
+/*\r
+\r
+    Name:       Railscasts\r
+    Author:     Ryan Bates (http://railscasts.com)\r
+\r
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\r
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\r
+\r
+*/\r
+\r
+.cm-s-railscasts.CodeMirror {background: #2b2b2b; color: #f4f1ed;}\r
+.cm-s-railscasts div.CodeMirror-selected {background: #272935 !important;}\r
+.cm-s-railscasts .CodeMirror-gutters {background: #2b2b2b; border-right: 0px;}\r
+.cm-s-railscasts .CodeMirror-linenumber {color: #5a647e;}\r
+.cm-s-railscasts .CodeMirror-cursor {border-left: 1px solid #d4cfc9 !important;}\r
+\r
+.cm-s-railscasts span.cm-comment {color: #bc9458;}\r
+.cm-s-railscasts span.cm-atom {color: #b6b3eb;}\r
+.cm-s-railscasts span.cm-number {color: #b6b3eb;}\r
+\r
+.cm-s-railscasts span.cm-property, .cm-s-railscasts span.cm-attribute {color: #a5c261;}\r
+.cm-s-railscasts span.cm-keyword {color: #da4939;}\r
+.cm-s-railscasts span.cm-string {color: #ffc66d;}\r
+\r
+.cm-s-railscasts span.cm-variable {color: #a5c261;}\r
+.cm-s-railscasts span.cm-variable-2 {color: #6d9cbe;}\r
+.cm-s-railscasts span.cm-def {color: #cc7833;}\r
+.cm-s-railscasts span.cm-error {background: #da4939; color: #d4cfc9;}\r
+.cm-s-railscasts span.cm-bracket {color: #f4f1ed;}\r
+.cm-s-railscasts span.cm-tag {color: #da4939;}\r
+.cm-s-railscasts span.cm-link {color: #b6b3eb;}\r
+\r
+.cm-s-railscasts .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\r
+.cm-s-railscasts .CodeMirror-activeline-background { background: #303040; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/rubyblue.css b/js/ckeditor/plugins/codemirror/theme/rubyblue.css
new file mode 100644 (file)
index 0000000..8d4c17f
--- /dev/null
@@ -0,0 +1,25 @@
+.cm-s-rubyblue.CodeMirror { background: #112435; color: white; }\r
+.cm-s-rubyblue div.CodeMirror-selected { background: #38566F; }\r
+.cm-s-rubyblue .CodeMirror-line::selection, .cm-s-rubyblue .CodeMirror-line > span::selection, .cm-s-rubyblue .CodeMirror-line > span > span::selection { background: rgba(56, 86, 111, 0.99); }\r
+.cm-s-rubyblue .CodeMirror-line::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span > span::-moz-selection { background: rgba(56, 86, 111, 0.99); }\r
+.cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; }\r
+.cm-s-rubyblue .CodeMirror-guttermarker { color: white; }\r
+.cm-s-rubyblue .CodeMirror-guttermarker-subtle { color: #3E7087; }\r
+.cm-s-rubyblue .CodeMirror-linenumber { color: white; }\r
+.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white; }\r
+\r
+.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; }\r
+.cm-s-rubyblue span.cm-atom { color: #F4C20B; }\r
+.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; }\r
+.cm-s-rubyblue span.cm-keyword { color: #F0F; }\r
+.cm-s-rubyblue span.cm-string { color: #F08047; }\r
+.cm-s-rubyblue span.cm-meta { color: #F0F; }\r
+.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }\r
+.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def, .cm-s-rubyblue span.cm-type { color: white; }\r
+.cm-s-rubyblue span.cm-bracket { color: #F0F; }\r
+.cm-s-rubyblue span.cm-link { color: #F4C20B; }\r
+.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; }\r
+.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; }\r
+.cm-s-rubyblue span.cm-error { color: #AF2018; }\r
+\r
+.cm-s-rubyblue .CodeMirror-activeline-background { background: #173047; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/seti.css b/js/ckeditor/plugins/codemirror/theme/seti.css
new file mode 100644 (file)
index 0000000..400f0a5
--- /dev/null
@@ -0,0 +1,44 @@
+/*\r
+\r
+    Name:       seti\r
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)\r
+\r
+    Original seti color scheme by Jesse Weed (https://github.com/jesseweed/seti-syntax)\r
+\r
+*/\r
+\r
+\r
+.cm-s-seti.CodeMirror {\r
+  background-color: #151718 !important;\r
+  color: #CFD2D1 !important;\r
+  border: none;\r
+}\r
+.cm-s-seti .CodeMirror-gutters {\r
+  color: #404b53;\r
+  background-color: #0E1112;\r
+  border: none;\r
+}\r
+.cm-s-seti .CodeMirror-cursor { border-left: solid thin #f8f8f0; }\r
+.cm-s-seti .CodeMirror-linenumber { color: #6D8A88; }\r
+.cm-s-seti.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-seti .CodeMirror-line::selection, .cm-s-seti .CodeMirror-line > span::selection, .cm-s-seti .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-seti .CodeMirror-line::-moz-selection, .cm-s-seti .CodeMirror-line > span::-moz-selection, .cm-s-seti .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }\r
+.cm-s-seti span.cm-comment { color: #41535b; }\r
+.cm-s-seti span.cm-string, .cm-s-seti span.cm-string-2 { color: #55b5db; }\r
+.cm-s-seti span.cm-number { color: #cd3f45; }\r
+.cm-s-seti span.cm-variable { color: #55b5db; }\r
+.cm-s-seti span.cm-variable-2 { color: #a074c4; }\r
+.cm-s-seti span.cm-def { color: #55b5db; }\r
+.cm-s-seti span.cm-keyword { color: #ff79c6; }\r
+.cm-s-seti span.cm-operator { color: #9fca56; }\r
+.cm-s-seti span.cm-keyword { color: #e6cd69; }\r
+.cm-s-seti span.cm-atom { color: #cd3f45; }\r
+.cm-s-seti span.cm-meta { color: #55b5db; }\r
+.cm-s-seti span.cm-tag { color: #55b5db; }\r
+.cm-s-seti span.cm-attribute { color: #9fca56; }\r
+.cm-s-seti span.cm-qualifier { color: #9fca56; }\r
+.cm-s-seti span.cm-property { color: #a074c4; }\r
+.cm-s-seti span.cm-variable-3, .cm-s-seti span.cm-type { color: #9fca56; }\r
+.cm-s-seti span.cm-builtin { color: #9fca56; }\r
+.cm-s-seti .CodeMirror-activeline-background { background: #101213; }\r
+.cm-s-seti .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/solarized.css b/js/ckeditor/plugins/codemirror/theme/solarized.css
new file mode 100644 (file)
index 0000000..44777cb
--- /dev/null
@@ -0,0 +1,169 @@
+/*\r
+Solarized theme for code-mirror\r
+http://ethanschoonover.com/solarized\r
+*/\r
+\r
+/*\r
+Solarized color palette\r
+http://ethanschoonover.com/solarized/img/solarized-palette.png\r
+*/\r
+\r
+.solarized.base03 { color: #002b36; }\r
+.solarized.base02 { color: #073642; }\r
+.solarized.base01 { color: #586e75; }\r
+.solarized.base00 { color: #657b83; }\r
+.solarized.base0 { color: #839496; }\r
+.solarized.base1 { color: #93a1a1; }\r
+.solarized.base2 { color: #eee8d5; }\r
+.solarized.base3  { color: #fdf6e3; }\r
+.solarized.solar-yellow  { color: #b58900; }\r
+.solarized.solar-orange  { color: #cb4b16; }\r
+.solarized.solar-red { color: #dc322f; }\r
+.solarized.solar-magenta { color: #d33682; }\r
+.solarized.solar-violet  { color: #6c71c4; }\r
+.solarized.solar-blue { color: #268bd2; }\r
+.solarized.solar-cyan { color: #2aa198; }\r
+.solarized.solar-green { color: #859900; }\r
+\r
+/* Color scheme for code-mirror */\r
+\r
+.cm-s-solarized {\r
+  line-height: 1.45em;\r
+  color-profile: sRGB;\r
+  rendering-intent: auto;\r
+}\r
+.cm-s-solarized.cm-s-dark {\r
+  color: #839496;\r
+  background-color: #002b36;\r
+  text-shadow: #002b36 0 1px;\r
+}\r
+.cm-s-solarized.cm-s-light {\r
+  background-color: #fdf6e3;\r
+  color: #657b83;\r
+  text-shadow: #eee8d5 0 1px;\r
+}\r
+\r
+.cm-s-solarized .CodeMirror-widget {\r
+  text-shadow: none;\r
+}\r
+\r
+.cm-s-solarized .cm-header { color: #586e75; }\r
+.cm-s-solarized .cm-quote { color: #93a1a1; }\r
+\r
+.cm-s-solarized .cm-keyword { color: #cb4b16; }\r
+.cm-s-solarized .cm-atom { color: #d33682; }\r
+.cm-s-solarized .cm-number { color: #d33682; }\r
+.cm-s-solarized .cm-def { color: #2aa198; }\r
+\r
+.cm-s-solarized .cm-variable { color: #839496; }\r
+.cm-s-solarized .cm-variable-2 { color: #b58900; }\r
+.cm-s-solarized .cm-variable-3, .cm-s-solarized .cm-type { color: #6c71c4; }\r
+\r
+.cm-s-solarized .cm-property { color: #2aa198; }\r
+.cm-s-solarized .cm-operator { color: #6c71c4; }\r
+\r
+.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; }\r
+\r
+.cm-s-solarized .cm-string { color: #859900; }\r
+.cm-s-solarized .cm-string-2 { color: #b58900; }\r
+\r
+.cm-s-solarized .cm-meta { color: #859900; }\r
+.cm-s-solarized .cm-qualifier { color: #b58900; }\r
+.cm-s-solarized .cm-builtin { color: #d33682; }\r
+.cm-s-solarized .cm-bracket { color: #cb4b16; }\r
+.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; }\r
+.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; }\r
+.cm-s-solarized .cm-tag { color: #93a1a1; }\r
+.cm-s-solarized .cm-attribute { color: #2aa198; }\r
+.cm-s-solarized .cm-hr {\r
+  color: transparent;\r
+  border-top: 1px solid #586e75;\r
+  display: block;\r
+}\r
+.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; }\r
+.cm-s-solarized .cm-special { color: #6c71c4; }\r
+.cm-s-solarized .cm-em {\r
+  color: #999;\r
+  text-decoration: underline;\r
+  text-decoration-style: dotted;\r
+}\r
+.cm-s-solarized .cm-strong { color: #eee; }\r
+.cm-s-solarized .cm-error,\r
+.cm-s-solarized .cm-invalidchar {\r
+  color: #586e75;\r
+  border-bottom: 1px dotted #dc322f;\r
+}\r
+\r
+.cm-s-solarized.cm-s-dark div.CodeMirror-selected { background: #073642; }\r
+.cm-s-solarized.cm-s-dark.CodeMirror ::selection { background: rgba(7, 54, 66, 0.99); }\r
+.cm-s-solarized.cm-s-dark .CodeMirror-line::-moz-selection, .cm-s-dark .CodeMirror-line > span::-moz-selection, .cm-s-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(7, 54, 66, 0.99); }\r
+\r
+.cm-s-solarized.cm-s-light div.CodeMirror-selected { background: #eee8d5; }\r
+.cm-s-solarized.cm-s-light .CodeMirror-line::selection, .cm-s-light .CodeMirror-line > span::selection, .cm-s-light .CodeMirror-line > span > span::selection { background: #eee8d5; }\r
+.cm-s-solarized.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-ligh .CodeMirror-line > span::-moz-selection, .cm-s-ligh .CodeMirror-line > span > span::-moz-selection { background: #eee8d5; }\r
+\r
+/* Editor styling */\r
+\r
+\r
+\r
+/* Little shadow on the view-port of the buffer view */\r
+.cm-s-solarized.CodeMirror {\r
+  -moz-box-shadow: inset 7px 0 12px -6px #000;\r
+  -webkit-box-shadow: inset 7px 0 12px -6px #000;\r
+  box-shadow: inset 7px 0 12px -6px #000;\r
+}\r
+\r
+/* Remove gutter border */\r
+.cm-s-solarized .CodeMirror-gutters {\r
+  border-right: 0;\r
+}\r
+\r
+/* Gutter colors and line number styling based of color scheme (dark / light) */\r
+\r
+/* Dark */\r
+.cm-s-solarized.cm-s-dark .CodeMirror-gutters {\r
+  background-color: #073642;\r
+}\r
+\r
+.cm-s-solarized.cm-s-dark .CodeMirror-linenumber {\r
+  color: #586e75;\r
+  text-shadow: #021014 0 -1px;\r
+}\r
+\r
+/* Light */\r
+.cm-s-solarized.cm-s-light .CodeMirror-gutters {\r
+  background-color: #eee8d5;\r
+}\r
+\r
+.cm-s-solarized.cm-s-light .CodeMirror-linenumber {\r
+  color: #839496;\r
+}\r
+\r
+/* Common */\r
+.cm-s-solarized .CodeMirror-linenumber {\r
+  padding: 0 5px;\r
+}\r
+.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; }\r
+.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; }\r
+.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; }\r
+\r
+.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text {\r
+  color: #586e75;\r
+}\r
+\r
+/* Cursor */\r
+.cm-s-solarized .CodeMirror-cursor { border-left: 1px solid #819090; }\r
+\r
+/* Fat cursor */\r
+.cm-s-solarized.cm-s-light.cm-fat-cursor .CodeMirror-cursor { background: #77ee77; }\r
+.cm-s-solarized.cm-s-light .cm-animate-fat-cursor { background-color: #77ee77; }\r
+.cm-s-solarized.cm-s-dark.cm-fat-cursor .CodeMirror-cursor { background: #586e75; }\r
+.cm-s-solarized.cm-s-dark .cm-animate-fat-cursor { background-color: #586e75; }\r
+\r
+/* Active line */\r
+.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {\r
+  background: rgba(255, 255, 255, 0.06);\r
+}\r
+.cm-s-solarized.cm-s-light .CodeMirror-activeline-background {\r
+  background: rgba(0, 0, 0, 0.06);\r
+}\r
diff --git a/js/ckeditor/plugins/codemirror/theme/the-matrix.css b/js/ckeditor/plugins/codemirror/theme/the-matrix.css
new file mode 100644 (file)
index 0000000..2106c19
--- /dev/null
@@ -0,0 +1,30 @@
+.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; }\r
+.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D; }\r
+.cm-s-the-matrix .CodeMirror-line::selection, .cm-s-the-matrix .CodeMirror-line > span::selection, .cm-s-the-matrix .CodeMirror-line > span > span::selection { background: rgba(45, 45, 45, 0.99); }\r
+.cm-s-the-matrix .CodeMirror-line::-moz-selection, .cm-s-the-matrix .CodeMirror-line > span::-moz-selection, .cm-s-the-matrix .CodeMirror-line > span > span::-moz-selection { background: rgba(45, 45, 45, 0.99); }\r
+.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; }\r
+.cm-s-the-matrix .CodeMirror-guttermarker { color: #0f0; }\r
+.cm-s-the-matrix .CodeMirror-guttermarker-subtle { color: white; }\r
+.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; }\r
+.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00; }\r
+\r
+.cm-s-the-matrix span.cm-keyword { color: #008803; font-weight: bold; }\r
+.cm-s-the-matrix span.cm-atom { color: #3FF; }\r
+.cm-s-the-matrix span.cm-number { color: #FFB94F; }\r
+.cm-s-the-matrix span.cm-def { color: #99C; }\r
+.cm-s-the-matrix span.cm-variable { color: #F6C; }\r
+.cm-s-the-matrix span.cm-variable-2 { color: #C6F; }\r
+.cm-s-the-matrix span.cm-variable-3, .cm-s-the-matrix span.cm-type { color: #96F; }\r
+.cm-s-the-matrix span.cm-property { color: #62FFA0; }\r
+.cm-s-the-matrix span.cm-operator { color: #999; }\r
+.cm-s-the-matrix span.cm-comment { color: #CCCCCC; }\r
+.cm-s-the-matrix span.cm-string { color: #39C; }\r
+.cm-s-the-matrix span.cm-meta { color: #C9F; }\r
+.cm-s-the-matrix span.cm-qualifier { color: #FFF700; }\r
+.cm-s-the-matrix span.cm-builtin { color: #30a; }\r
+.cm-s-the-matrix span.cm-bracket { color: #cc7; }\r
+.cm-s-the-matrix span.cm-tag { color: #FFBD40; }\r
+.cm-s-the-matrix span.cm-attribute { color: #FFF700; }\r
+.cm-s-the-matrix span.cm-error { color: #FF0000; }\r
+\r
+.cm-s-the-matrix .CodeMirror-activeline-background { background: #040; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/tomorrow-night-bright.css b/js/ckeditor/plugins/codemirror/theme/tomorrow-night-bright.css
new file mode 100644 (file)
index 0000000..5d567c7
--- /dev/null
@@ -0,0 +1,35 @@
+/*\r
+\r
+    Name:       Tomorrow Night - Bright\r
+    Author:     Chris Kempson\r
+\r
+    Port done by Gerard Braad <me@gbraad.nl>\r
+\r
+*/\r
+\r
+.cm-s-tomorrow-night-bright.CodeMirror { background: #000000; color: #eaeaea; }\r
+.cm-s-tomorrow-night-bright div.CodeMirror-selected { background: #424242; }\r
+.cm-s-tomorrow-night-bright .CodeMirror-gutters { background: #000000; border-right: 0px; }\r
+.cm-s-tomorrow-night-bright .CodeMirror-guttermarker { color: #e78c45; }\r
+.cm-s-tomorrow-night-bright .CodeMirror-guttermarker-subtle { color: #777; }\r
+.cm-s-tomorrow-night-bright .CodeMirror-linenumber { color: #424242; }\r
+.cm-s-tomorrow-night-bright .CodeMirror-cursor { border-left: 1px solid #6A6A6A; }\r
+\r
+.cm-s-tomorrow-night-bright span.cm-comment { color: #d27b53; }\r
+.cm-s-tomorrow-night-bright span.cm-atom { color: #a16a94; }\r
+.cm-s-tomorrow-night-bright span.cm-number { color: #a16a94; }\r
+\r
+.cm-s-tomorrow-night-bright span.cm-property, .cm-s-tomorrow-night-bright span.cm-attribute { color: #99cc99; }\r
+.cm-s-tomorrow-night-bright span.cm-keyword { color: #d54e53; }\r
+.cm-s-tomorrow-night-bright span.cm-string { color: #e7c547; }\r
+\r
+.cm-s-tomorrow-night-bright span.cm-variable { color: #b9ca4a; }\r
+.cm-s-tomorrow-night-bright span.cm-variable-2 { color: #7aa6da; }\r
+.cm-s-tomorrow-night-bright span.cm-def { color: #e78c45; }\r
+.cm-s-tomorrow-night-bright span.cm-bracket { color: #eaeaea; }\r
+.cm-s-tomorrow-night-bright span.cm-tag { color: #d54e53; }\r
+.cm-s-tomorrow-night-bright span.cm-link { color: #a16a94; }\r
+.cm-s-tomorrow-night-bright span.cm-error { background: #d54e53; color: #6A6A6A; }\r
+\r
+.cm-s-tomorrow-night-bright .CodeMirror-activeline-background { background: #2a2a2a; }\r
+.cm-s-tomorrow-night-bright .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/tomorrow-night-eighties.css b/js/ckeditor/plugins/codemirror/theme/tomorrow-night-eighties.css
new file mode 100644 (file)
index 0000000..0eef9fe
--- /dev/null
@@ -0,0 +1,38 @@
+/*\r
+\r
+    Name:       Tomorrow Night - Eighties\r
+    Author:     Chris Kempson\r
+\r
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\r
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\r
+\r
+*/\r
+\r
+.cm-s-tomorrow-night-eighties.CodeMirror { background: #000000; color: #CCCCCC; }\r
+.cm-s-tomorrow-night-eighties div.CodeMirror-selected { background: #2D2D2D; }\r
+.cm-s-tomorrow-night-eighties .CodeMirror-line::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::selection { background: rgba(45, 45, 45, 0.99); }\r
+.cm-s-tomorrow-night-eighties .CodeMirror-line::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::-moz-selection { background: rgba(45, 45, 45, 0.99); }\r
+.cm-s-tomorrow-night-eighties .CodeMirror-gutters { background: #000000; border-right: 0px; }\r
+.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker { color: #f2777a; }\r
+.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker-subtle { color: #777; }\r
+.cm-s-tomorrow-night-eighties .CodeMirror-linenumber { color: #515151; }\r
+.cm-s-tomorrow-night-eighties .CodeMirror-cursor { border-left: 1px solid #6A6A6A; }\r
+\r
+.cm-s-tomorrow-night-eighties span.cm-comment { color: #d27b53; }\r
+.cm-s-tomorrow-night-eighties span.cm-atom { color: #a16a94; }\r
+.cm-s-tomorrow-night-eighties span.cm-number { color: #a16a94; }\r
+\r
+.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute { color: #99cc99; }\r
+.cm-s-tomorrow-night-eighties span.cm-keyword { color: #f2777a; }\r
+.cm-s-tomorrow-night-eighties span.cm-string { color: #ffcc66; }\r
+\r
+.cm-s-tomorrow-night-eighties span.cm-variable { color: #99cc99; }\r
+.cm-s-tomorrow-night-eighties span.cm-variable-2 { color: #6699cc; }\r
+.cm-s-tomorrow-night-eighties span.cm-def { color: #f99157; }\r
+.cm-s-tomorrow-night-eighties span.cm-bracket { color: #CCCCCC; }\r
+.cm-s-tomorrow-night-eighties span.cm-tag { color: #f2777a; }\r
+.cm-s-tomorrow-night-eighties span.cm-link { color: #a16a94; }\r
+.cm-s-tomorrow-night-eighties span.cm-error { background: #f2777a; color: #6A6A6A; }\r
+\r
+.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background { background: #343600; }\r
+.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/ttcn.css b/js/ckeditor/plugins/codemirror/theme/ttcn.css
new file mode 100644 (file)
index 0000000..69c9a09
--- /dev/null
@@ -0,0 +1,64 @@
+.cm-s-ttcn .cm-quote { color: #090; }\r
+.cm-s-ttcn .cm-negative { color: #d44; }\r
+.cm-s-ttcn .cm-positive { color: #292; }\r
+.cm-s-ttcn .cm-header, .cm-strong { font-weight: bold; }\r
+.cm-s-ttcn .cm-em { font-style: italic; }\r
+.cm-s-ttcn .cm-link { text-decoration: underline; }\r
+.cm-s-ttcn .cm-strikethrough { text-decoration: line-through; }\r
+.cm-s-ttcn .cm-header { color: #00f; font-weight: bold; }\r
+\r
+.cm-s-ttcn .cm-atom { color: #219; }\r
+.cm-s-ttcn .cm-attribute { color: #00c; }\r
+.cm-s-ttcn .cm-bracket { color: #997; }\r
+.cm-s-ttcn .cm-comment { color: #333333; }\r
+.cm-s-ttcn .cm-def { color: #00f; }\r
+.cm-s-ttcn .cm-em { font-style: italic; }\r
+.cm-s-ttcn .cm-error { color: #f00; }\r
+.cm-s-ttcn .cm-hr { color: #999; }\r
+.cm-s-ttcn .cm-invalidchar { color: #f00; }\r
+.cm-s-ttcn .cm-keyword { font-weight:bold; }\r
+.cm-s-ttcn .cm-link { color: #00c; text-decoration: underline; }\r
+.cm-s-ttcn .cm-meta { color: #555; }\r
+.cm-s-ttcn .cm-negative { color: #d44; }\r
+.cm-s-ttcn .cm-positive { color: #292; }\r
+.cm-s-ttcn .cm-qualifier { color: #555; }\r
+.cm-s-ttcn .cm-strikethrough { text-decoration: line-through; }\r
+.cm-s-ttcn .cm-string { color: #006400; }\r
+.cm-s-ttcn .cm-string-2 { color: #f50; }\r
+.cm-s-ttcn .cm-strong { font-weight: bold; }\r
+.cm-s-ttcn .cm-tag { color: #170; }\r
+.cm-s-ttcn .cm-variable { color: #8B2252; }\r
+.cm-s-ttcn .cm-variable-2 { color: #05a; }\r
+.cm-s-ttcn .cm-variable-3, .cm-s-ttcn .cm-type { color: #085; }\r
+\r
+.cm-s-ttcn .cm-invalidchar { color: #f00; }\r
+\r
+/* ASN */\r
+.cm-s-ttcn .cm-accessTypes,\r
+.cm-s-ttcn .cm-compareTypes { color: #27408B; }\r
+.cm-s-ttcn .cm-cmipVerbs { color: #8B2252; }\r
+.cm-s-ttcn .cm-modifier { color:#D2691E; }\r
+.cm-s-ttcn .cm-status { color:#8B4545; }\r
+.cm-s-ttcn .cm-storage { color:#A020F0; }\r
+.cm-s-ttcn .cm-tags { color:#006400; }\r
+\r
+/* CFG */\r
+.cm-s-ttcn .cm-externalCommands { color: #8B4545; font-weight:bold; }\r
+.cm-s-ttcn .cm-fileNCtrlMaskOptions,\r
+.cm-s-ttcn .cm-sectionTitle { color: #2E8B57; font-weight:bold; }\r
+\r
+/* TTCN */\r
+.cm-s-ttcn .cm-booleanConsts,\r
+.cm-s-ttcn .cm-otherConsts,\r
+.cm-s-ttcn .cm-verdictConsts { color: #006400; }\r
+.cm-s-ttcn .cm-configOps,\r
+.cm-s-ttcn .cm-functionOps,\r
+.cm-s-ttcn .cm-portOps,\r
+.cm-s-ttcn .cm-sutOps,\r
+.cm-s-ttcn .cm-timerOps,\r
+.cm-s-ttcn .cm-verdictOps { color: #0000FF; }\r
+.cm-s-ttcn .cm-preprocessor,\r
+.cm-s-ttcn .cm-templateMatch,\r
+.cm-s-ttcn .cm-ttcn3Macros { color: #27408B; }\r
+.cm-s-ttcn .cm-types { color: #A52A2A; font-weight:bold; }\r
+.cm-s-ttcn .cm-visibilityModifiers { font-weight:bold; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/twilight.css b/js/ckeditor/plugins/codemirror/theme/twilight.css
new file mode 100644 (file)
index 0000000..8e6cb74
--- /dev/null
@@ -0,0 +1,32 @@
+.cm-s-twilight.CodeMirror { background: #141414; color: #f7f7f7; } /**/\r
+.cm-s-twilight div.CodeMirror-selected { background: #323232; } /**/\r
+.cm-s-twilight .CodeMirror-line::selection, .cm-s-twilight .CodeMirror-line > span::selection, .cm-s-twilight .CodeMirror-line > span > span::selection { background: rgba(50, 50, 50, 0.99); }\r
+.cm-s-twilight .CodeMirror-line::-moz-selection, .cm-s-twilight .CodeMirror-line > span::-moz-selection, .cm-s-twilight .CodeMirror-line > span > span::-moz-selection { background: rgba(50, 50, 50, 0.99); }\r
+\r
+.cm-s-twilight .CodeMirror-gutters { background: #222; border-right: 1px solid #aaa; }\r
+.cm-s-twilight .CodeMirror-guttermarker { color: white; }\r
+.cm-s-twilight .CodeMirror-guttermarker-subtle { color: #aaa; }\r
+.cm-s-twilight .CodeMirror-linenumber { color: #aaa; }\r
+.cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white; }\r
+\r
+.cm-s-twilight .cm-keyword { color: #f9ee98; } /**/\r
+.cm-s-twilight .cm-atom { color: #FC0; }\r
+.cm-s-twilight .cm-number { color:  #ca7841; } /**/\r
+.cm-s-twilight .cm-def { color: #8DA6CE; }\r
+.cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/\r
+.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def, .cm-s-twilight span.cm-type { color: #607392; } /**/\r
+.cm-s-twilight .cm-operator { color: #cda869; } /**/\r
+.cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/\r
+.cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/\r
+.cm-s-twilight .cm-string-2 { color:#bd6b18; } /*?*/\r
+.cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/\r
+.cm-s-twilight .cm-builtin { color: #cda869; } /*?*/\r
+.cm-s-twilight .cm-tag { color: #997643; } /**/\r
+.cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/\r
+.cm-s-twilight .cm-header { color: #FF6400; }\r
+.cm-s-twilight .cm-hr { color: #AEAEAE; }\r
+.cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/\r
+.cm-s-twilight .cm-error { border-bottom: 1px solid red; }\r
+\r
+.cm-s-twilight .CodeMirror-activeline-background { background: #27282E; }\r
+.cm-s-twilight .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/vibrant-ink.css b/js/ckeditor/plugins/codemirror/theme/vibrant-ink.css
new file mode 100644 (file)
index 0000000..e900195
--- /dev/null
@@ -0,0 +1,34 @@
+/* Taken from the popular Visual Studio Vibrant Ink Schema */\r
+\r
+.cm-s-vibrant-ink.CodeMirror { background: black; color: white; }\r
+.cm-s-vibrant-ink div.CodeMirror-selected { background: #35493c; }\r
+.cm-s-vibrant-ink .CodeMirror-line::selection, .cm-s-vibrant-ink .CodeMirror-line > span::selection, .cm-s-vibrant-ink .CodeMirror-line > span > span::selection { background: rgba(53, 73, 60, 0.99); }\r
+.cm-s-vibrant-ink .CodeMirror-line::-moz-selection, .cm-s-vibrant-ink .CodeMirror-line > span::-moz-selection, .cm-s-vibrant-ink .CodeMirror-line > span > span::-moz-selection { background: rgba(53, 73, 60, 0.99); }\r
+\r
+.cm-s-vibrant-ink .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }\r
+.cm-s-vibrant-ink .CodeMirror-guttermarker { color: white; }\r
+.cm-s-vibrant-ink .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\r
+.cm-s-vibrant-ink .CodeMirror-linenumber { color: #d0d0d0; }\r
+.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white; }\r
+\r
+.cm-s-vibrant-ink .cm-keyword { color: #CC7832; }\r
+.cm-s-vibrant-ink .cm-atom { color: #FC0; }\r
+.cm-s-vibrant-ink .cm-number { color:  #FFEE98; }\r
+.cm-s-vibrant-ink .cm-def { color: #8DA6CE; }\r
+.cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D; }\r
+.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def, .cm-s-vibrant span.cm-type { color: #FFC66D; }\r
+.cm-s-vibrant-ink .cm-operator { color: #888; }\r
+.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; }\r
+.cm-s-vibrant-ink .cm-string { color:  #A5C25C; }\r
+.cm-s-vibrant-ink .cm-string-2 { color: red; }\r
+.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; }\r
+.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; }\r
+.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; }\r
+.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; }\r
+.cm-s-vibrant-ink .cm-header { color: #FF6400; }\r
+.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; }\r
+.cm-s-vibrant-ink .cm-link { color: blue; }\r
+.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }\r
+\r
+.cm-s-vibrant-ink .CodeMirror-activeline-background { background: #27282E; }\r
+.cm-s-vibrant-ink .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/xq-dark.css b/js/ckeditor/plugins/codemirror/theme/xq-dark.css
new file mode 100644 (file)
index 0000000..039b5a0
--- /dev/null
@@ -0,0 +1,53 @@
+/*\r
+Copyright (C) 2011 by MarkLogic Corporation\r
+Author: Mike Brevoort <mike@brevoort.com>\r
+\r
+Permission is hereby granted, free of charge, to any person obtaining a copy\r
+of this software and associated documentation files (the "Software"), to deal\r
+in the Software without restriction, including without limitation the rights\r
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+copies of the Software, and to permit persons to whom the Software is\r
+furnished to do so, subject to the following conditions:\r
+\r
+The above copyright notice and this permission notice shall be included in\r
+all copies or substantial portions of the Software.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
+THE SOFTWARE.\r
+*/\r
+.cm-s-xq-dark.CodeMirror { background: #0a001f; color: #f8f8f8; }\r
+.cm-s-xq-dark div.CodeMirror-selected { background: #27007A; }\r
+.cm-s-xq-dark .CodeMirror-line::selection, .cm-s-xq-dark .CodeMirror-line > span::selection, .cm-s-xq-dark .CodeMirror-line > span > span::selection { background: rgba(39, 0, 122, 0.99); }\r
+.cm-s-xq-dark .CodeMirror-line::-moz-selection, .cm-s-xq-dark .CodeMirror-line > span::-moz-selection, .cm-s-xq-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(39, 0, 122, 0.99); }\r
+.cm-s-xq-dark .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }\r
+.cm-s-xq-dark .CodeMirror-guttermarker { color: #FFBD40; }\r
+.cm-s-xq-dark .CodeMirror-guttermarker-subtle { color: #f8f8f8; }\r
+.cm-s-xq-dark .CodeMirror-linenumber { color: #f8f8f8; }\r
+.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white; }\r
+\r
+.cm-s-xq-dark span.cm-keyword { color: #FFBD40; }\r
+.cm-s-xq-dark span.cm-atom { color: #6C8CD5; }\r
+.cm-s-xq-dark span.cm-number { color: #164; }\r
+.cm-s-xq-dark span.cm-def { color: #FFF; text-decoration:underline; }\r
+.cm-s-xq-dark span.cm-variable { color: #FFF; }\r
+.cm-s-xq-dark span.cm-variable-2 { color: #EEE; }\r
+.cm-s-xq-dark span.cm-variable-3, .cm-s-xq-dark span.cm-type { color: #DDD; }\r
+.cm-s-xq-dark span.cm-property {}\r
+.cm-s-xq-dark span.cm-operator {}\r
+.cm-s-xq-dark span.cm-comment { color: gray; }\r
+.cm-s-xq-dark span.cm-string { color: #9FEE00; }\r
+.cm-s-xq-dark span.cm-meta { color: yellow; }\r
+.cm-s-xq-dark span.cm-qualifier { color: #FFF700; }\r
+.cm-s-xq-dark span.cm-builtin { color: #30a; }\r
+.cm-s-xq-dark span.cm-bracket { color: #cc7; }\r
+.cm-s-xq-dark span.cm-tag { color: #FFBD40; }\r
+.cm-s-xq-dark span.cm-attribute { color: #FFF700; }\r
+.cm-s-xq-dark span.cm-error { color: #f00; }\r
+\r
+.cm-s-xq-dark .CodeMirror-activeline-background { background: #27282E; }\r
+.cm-s-xq-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/xq-light.css b/js/ckeditor/plugins/codemirror/theme/xq-light.css
new file mode 100644 (file)
index 0000000..1c6c63b
--- /dev/null
@@ -0,0 +1,43 @@
+/*\r
+Copyright (C) 2011 by MarkLogic Corporation\r
+Author: Mike Brevoort <mike@brevoort.com>\r
+\r
+Permission is hereby granted, free of charge, to any person obtaining a copy\r
+of this software and associated documentation files (the "Software"), to deal\r
+in the Software without restriction, including without limitation the rights\r
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+copies of the Software, and to permit persons to whom the Software is\r
+furnished to do so, subject to the following conditions:\r
+\r
+The above copyright notice and this permission notice shall be included in\r
+all copies or substantial portions of the Software.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
+THE SOFTWARE.\r
+*/\r
+.cm-s-xq-light span.cm-keyword { line-height: 1em; font-weight: bold; color: #5A5CAD; }\r
+.cm-s-xq-light span.cm-atom { color: #6C8CD5; }\r
+.cm-s-xq-light span.cm-number { color: #164; }\r
+.cm-s-xq-light span.cm-def { text-decoration:underline; }\r
+.cm-s-xq-light span.cm-variable { color: black; }\r
+.cm-s-xq-light span.cm-variable-2 { color:black; }\r
+.cm-s-xq-light span.cm-variable-3, .cm-s-xq-light span.cm-type { color: black; }\r
+.cm-s-xq-light span.cm-property {}\r
+.cm-s-xq-light span.cm-operator {}\r
+.cm-s-xq-light span.cm-comment { color: #0080FF; font-style: italic; }\r
+.cm-s-xq-light span.cm-string { color: red; }\r
+.cm-s-xq-light span.cm-meta { color: yellow; }\r
+.cm-s-xq-light span.cm-qualifier { color: grey; }\r
+.cm-s-xq-light span.cm-builtin { color: #7EA656; }\r
+.cm-s-xq-light span.cm-bracket { color: #cc7; }\r
+.cm-s-xq-light span.cm-tag { color: #3F7F7F; }\r
+.cm-s-xq-light span.cm-attribute { color: #7F007F; }\r
+.cm-s-xq-light span.cm-error { color: #f00; }\r
+\r
+.cm-s-xq-light .CodeMirror-activeline-background { background: #e8f2ff; }\r
+.cm-s-xq-light .CodeMirror-matchingbracket { outline:1px solid grey;color:black !important;background:yellow; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/yeti.css b/js/ckeditor/plugins/codemirror/theme/yeti.css
new file mode 100644 (file)
index 0000000..1edc1dd
--- /dev/null
@@ -0,0 +1,44 @@
+/*\r
+\r
+    Name:       yeti\r
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)\r
+\r
+    Original yeti color scheme by Jesse Weed (https://github.com/jesseweed/yeti-syntax)\r
+\r
+*/\r
+\r
+\r
+.cm-s-yeti.CodeMirror {\r
+  background-color: #ECEAE8 !important;\r
+  color: #d1c9c0 !important;\r
+  border: none;\r
+}\r
+\r
+.cm-s-yeti .CodeMirror-gutters {\r
+  color: #adaba6;\r
+  background-color: #E5E1DB;\r
+  border: none;\r
+}\r
+.cm-s-yeti .CodeMirror-cursor { border-left: solid thin #d1c9c0; }\r
+.cm-s-yeti .CodeMirror-linenumber { color: #adaba6; }\r
+.cm-s-yeti.CodeMirror-focused div.CodeMirror-selected { background: #DCD8D2; }\r
+.cm-s-yeti .CodeMirror-line::selection, .cm-s-yeti .CodeMirror-line > span::selection, .cm-s-yeti .CodeMirror-line > span > span::selection { background: #DCD8D2; }\r
+.cm-s-yeti .CodeMirror-line::-moz-selection, .cm-s-yeti .CodeMirror-line > span::-moz-selection, .cm-s-yeti .CodeMirror-line > span > span::-moz-selection { background: #DCD8D2; }\r
+.cm-s-yeti span.cm-comment { color: #d4c8be; }\r
+.cm-s-yeti span.cm-string, .cm-s-yeti span.cm-string-2 { color: #96c0d8; }\r
+.cm-s-yeti span.cm-number { color: #a074c4; }\r
+.cm-s-yeti span.cm-variable { color: #55b5db; }\r
+.cm-s-yeti span.cm-variable-2 { color: #a074c4; }\r
+.cm-s-yeti span.cm-def { color: #55b5db; }\r
+.cm-s-yeti span.cm-operator { color: #9fb96e; }\r
+.cm-s-yeti span.cm-keyword { color: #9fb96e; }\r
+.cm-s-yeti span.cm-atom { color: #a074c4; }\r
+.cm-s-yeti span.cm-meta { color: #96c0d8; }\r
+.cm-s-yeti span.cm-tag { color: #96c0d8; }\r
+.cm-s-yeti span.cm-attribute { color: #9fb96e; }\r
+.cm-s-yeti span.cm-qualifier { color: #96c0d8; }\r
+.cm-s-yeti span.cm-property { color: #a074c4; }\r
+.cm-s-yeti span.cm-builtin { color: #a074c4; }\r
+.cm-s-yeti span.cm-variable-3, .cm-s-yeti span.cm-type { color: #96c0d8; }\r
+.cm-s-yeti .CodeMirror-activeline-background { background: #E7E4E0; }\r
+.cm-s-yeti .CodeMirror-matchingbracket { text-decoration: underline; }\r
diff --git a/js/ckeditor/plugins/codemirror/theme/zenburn.css b/js/ckeditor/plugins/codemirror/theme/zenburn.css
new file mode 100644 (file)
index 0000000..69cecea
--- /dev/null
@@ -0,0 +1,37 @@
+/**\r
+ * "\r
+ *  Using Zenburn color palette from the Emacs Zenburn Theme\r
+ *  https://github.com/bbatsov/zenburn-emacs/blob/master/zenburn-theme.el\r
+ *\r
+ *  Also using parts of https://github.com/xavi/coderay-lighttable-theme\r
+ * "\r
+ * From: https://github.com/wisenomad/zenburn-lighttable-theme/blob/master/zenburn.css\r
+ */\r
+\r
+.cm-s-zenburn .CodeMirror-gutters { background: #3f3f3f !important; }\r
+.cm-s-zenburn .CodeMirror-foldgutter-open, .CodeMirror-foldgutter-folded { color: #999; }\r
+.cm-s-zenburn .CodeMirror-cursor { border-left: 1px solid white; }\r
+.cm-s-zenburn { background-color: #3f3f3f; color: #dcdccc; }\r
+.cm-s-zenburn span.cm-builtin { color: #dcdccc; font-weight: bold; }\r
+.cm-s-zenburn span.cm-comment { color: #7f9f7f; }\r
+.cm-s-zenburn span.cm-keyword { color: #f0dfaf; font-weight: bold; }\r
+.cm-s-zenburn span.cm-atom { color: #bfebbf; }\r
+.cm-s-zenburn span.cm-def { color: #dcdccc; }\r
+.cm-s-zenburn span.cm-variable { color: #dfaf8f; }\r
+.cm-s-zenburn span.cm-variable-2 { color: #dcdccc; }\r
+.cm-s-zenburn span.cm-string { color: #cc9393; }\r
+.cm-s-zenburn span.cm-string-2 { color: #cc9393; }\r
+.cm-s-zenburn span.cm-number { color: #dcdccc; }\r
+.cm-s-zenburn span.cm-tag { color: #93e0e3; }\r
+.cm-s-zenburn span.cm-property { color: #dfaf8f; }\r
+.cm-s-zenburn span.cm-attribute { color: #dfaf8f; }\r
+.cm-s-zenburn span.cm-qualifier { color: #7cb8bb; }\r
+.cm-s-zenburn span.cm-meta { color: #f0dfaf; }\r
+.cm-s-zenburn span.cm-header { color: #f0efd0; }\r
+.cm-s-zenburn span.cm-operator { color: #f0efd0; }\r
+.cm-s-zenburn span.CodeMirror-matchingbracket { box-sizing: border-box; background: transparent; border-bottom: 1px solid; }\r
+.cm-s-zenburn span.CodeMirror-nonmatchingbracket { border-bottom: 1px solid; background: none; }\r
+.cm-s-zenburn .CodeMirror-activeline { background: #000000; }\r
+.cm-s-zenburn .CodeMirror-activeline-background { background: #000000; }\r
+.cm-s-zenburn div.CodeMirror-selected { background: #545454; }\r
+.cm-s-zenburn .CodeMirror-focused div.CodeMirror-selected { background: #4f4f4f; }\r
index e1e9e4a..ad22906 100644 (file)
Binary files a/js/ckeditor/plugins/icons.png and b/js/ckeditor/plugins/icons.png differ
index da3ef8d..7c76e52 100644 (file)
Binary files a/js/ckeditor/plugins/icons_hidpi.png and b/js/ckeditor/plugins/icons_hidpi.png differ
index 3ffb435..eefac2e 100644 (file)
     }
   });
 
+  function parentScroll(e) {
+    var position = e.$.getAttribute("position"),
+        excludeStaticParent = position === "absolute";
+    return e.getParents().filter( function(parent) {
+      var style = window.getComputedStyle(parent.$);
+      if ( excludeStaticParent && style.position === "static" )
+        return false;
+      return (/(auto|scroll)/).test( style['overflow'] + style["overflow-y"] + style["overflow-x"] );
+    });
+  };
+
+  function parentDialog(e) {
+    return e.getParents().filter( function(parent) {
+      return parent.$.classList.contains("ui-dialog-content")
+    })[0];
+  };
+
   function attach( editor ) {
-    var config = editor.config;
+    var config = editor.config,
+        parent = parentScroll(editor.element),
+        divelt = editor.element.getNext(function(elt){return elt.getAttribute("class") === "cke_textarea_inline"}),
+        inline = editor.element.$.classList.contains("texteditor-in-dialog");
+
+    var dialog;
+
+    if (inline) {
+      dialog = parentDialog(divelt);
+    }
 
     var resize = function (width, height) {
       var editable;
       var viewRect   = win.getViewPaneSize();
 
       float_space.setStyle( 'position', 'absolute' );
-      float_space.setStyle( 'top',    pixelate( editorPos.y + editorRect.height - floatRect.height + 1) );
-      float_space.setStyle( 'right',  pixelate( viewRect.width - editorRect.right ) );
+      if (inline) {
+        var dialogPos = dialog.getDocumentPosition();
+        float_space.setStyle( 'top',  pixelate( editorPos.y - dialogPos.y + editorRect.height - floatRect.height + 1 ) );
+
+        //float_space.setStyle( 'left', pixelate( editorPos.x - dialogPos.x + editorRect.width  - floatRect.width ) );
+        // floatRect.width seems to be far to high on first dialog popup
+        float_space.setStyle( 'left', pixelate( editorPos.x - dialogPos.x + editorRect.width  - 11 ) );
+      } else {
+        float_space.setStyle( 'top',    pixelate( editorPos.y + editorRect.height - floatRect.height + 1) );
+        float_space.setStyle( 'right',  pixelate( viewRect.width - editorRect.right ) );
+      }
     };
 
     var float_html  = '<div class="cke_editor_inline_resize_button">\u25E2</div>'; // class so that csss can overrise content and style
-    var float_space = CKEDITOR.document.getBody().append( CKEDITOR.dom.element.createFromHtml( float_html ));
+    var float_space = inline ? divelt.getParent().append( CKEDITOR.dom.element.createFromHtml( float_html ))
+                             : CKEDITOR.document.getBody().append( CKEDITOR.dom.element.createFromHtml( float_html ));
 
     var drag_handler = function( evt ) {
       var width  = startSize.width  + evt.data.$.screenX - origin.x,
       layout( evt );
     } );
 
+    parent.forEach(function(e){
+      e.on('scroll', function (evt) { layout(evt) });
+    });
+
     editor.on( 'blur', function() {
       float_space.hide();
     } );
    * ltr support
    * textarea/div mode safe, currently simply assumes that textarea inline is used
    * positioning of resize handle is not browser zomm safe
+   * positioning of resize handle in dialog with scroll bars is broken
 */
diff --git a/js/ckeditor/plugins/sourcedialog/dialogs/sourcedialog.js b/js/ckeditor/plugins/sourcedialog/dialogs/sourcedialog.js
new file mode 100644 (file)
index 0000000..048361c
--- /dev/null
@@ -0,0 +1,6 @@
+/*
+ Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.dialog.add("sourcedialog",function(a){var b=CKEDITOR.document.getWindow().getViewPaneSize(),e=Math.min(b.width-70,800),b=b.height/1.5,d;return{title:a.lang.sourcedialog.title,minWidth:100,minHeight:100,onShow:function(){this.setValueOf("main","data",d=a.getData())},onOk:function(){function b(f,c){a.focus();a.setData(c,function(){f.hide();var b=a.createRange();b.moveToElementEditStart(a.editable());b.select()})}return function(){var a=this.getValueOf("main","data").replace(/\r/g,""),c=this;
+if(a===d)return!0;setTimeout(function(){b(c,a)});return!1}}(),contents:[{id:"main",label:a.lang.sourcedialog.title,elements:[{type:"textarea",id:"data",dir:"ltr",inputStyle:"cursor:auto;width:"+e+"px;height:"+b+"px;tab-size:4;text-align:left;","class":"cke_source"}]}]}});
\ No newline at end of file
index 37ba9f8..aa51b70 100644 (file)
@@ -46,8 +46,8 @@ For licensing, see LICENSE.md or http://ckeditor.com/license
 \r
                        <h2 class="samples">Plugins</h2>
 <dl class="samples">
-<dt><a class="samples" href="wysiwygarea/fullpage.html">Full page support</a></dt>
-<dd>CKEditor inserted with a JavaScript call and used to edit the whole page from &lt;html&gt; to &lt;/html&gt;.</dd>
+<dt><a class="samples" href="sourcedialog/sourcedialog.html">Editing source code in a dialog</a><span class="new">New!</span></dt>
+<dd>Editing HTML content of both inline and classic editor instances.</dd>
 </dl>\r
                </div>\r
                <div class="twoColumnsRight">\r
diff --git a/js/ckeditor/samples/old/sourcedialog/sourcedialog.html b/js/ckeditor/samples/old/sourcedialog/sourcedialog.html
new file mode 100644 (file)
index 0000000..9232b0e
--- /dev/null
@@ -0,0 +1,121 @@
+<!DOCTYPE html>\r
+<!--\r
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
+For licensing, see LICENSE.md or http://ckeditor.com/license\r
+-->\r
+<html>\r
+<head>\r
+       <meta charset="utf-8">\r
+       <title>Editing source code in a dialog &mdash; CKEditor Sample</title>\r
+       <script src="../../../ckeditor.js"></script>\r
+       <link rel="stylesheet" href="../../../samples/old/sample.css">\r
+       <meta name="ckeditor-sample-name" content="Editing source code in a dialog">\r
+       <meta name="ckeditor-sample-group" content="Plugins">\r
+       <meta name="ckeditor-sample-description" content="Editing HTML content of both inline and classic editor instances.">\r
+       <meta name="ckeditor-sample-isnew" content="1">\r
+       <style>\r
+\r
+               #editable\r
+               {\r
+                       padding: 10px;\r
+                       float: left;\r
+               }\r
+\r
+       </style>\r
+</head>\r
+<body>\r
+       <h1 class="samples">\r
+               <a href="../../../samples/old/index.html">CKEditor Samples</a> &raquo; Editing source code in a dialog\r
+       </h1>\r
+       <div class="warning deprecated">\r
+               This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/sourcearea.html">brand new version in CKEditor SDK</a>.\r
+       </div>\r
+       <div class="description">\r
+               <p>\r
+                       <strong>Sourcedialog</strong> plugin provides an easy way to edit raw HTML content\r
+                       of an editor, similarly to what is possible with <strong>Sourcearea</strong>\r
+                       plugin for classic (<code>iframe</code>-based) instances but using dialogs. Thanks to that, it's also possible\r
+                       to manipulate raw content of inline editor instances.\r
+               </p>\r
+               <p>\r
+                       This plugin extends the toolbar with a button,\r
+                       which opens a dialog window with a source code editor. It works with both classic\r
+                       and inline instances. To enable this\r
+                       plugin, basically add <code>extraPlugins: 'sourcedialog'</code> to editor's\r
+                       config:\r
+               </p>\r
+<pre class="samples">\r
+// Inline editor.\r
+CKEDITOR.inline( 'editable', {\r
+       <strong>extraPlugins: 'sourcedialog'</strong>\r
+});\r
+\r
+// Classic (iframe-based) editor.\r
+CKEDITOR.replace( 'textarea_id', {\r
+       <strong>extraPlugins: 'sourcedialog'</strong>,\r
+       removePlugins: 'sourcearea'\r
+});\r
+</pre>\r
+               <p>\r
+                       Note that you may want to include <code>removePlugins: 'sourcearea'</code>\r
+                       in your config when using <strong>Sourcedialog</strong> in classic editor instances.\r
+                       This prevents feature redundancy.\r
+               </p>\r
+               <p>\r
+                       Note that <code>editable</code> in the code above is the <code>id</code>\r
+                       attribute of the <code>&lt;div&gt;</code> element to be converted into an inline instance.\r
+               </p>\r
+               <p>\r
+                       Note that <code><em>textarea_id</em></code> in the code above is the <code>id</code> attribute of\r
+                       the <code>&lt;textarea&gt;</code> element to be replaced with CKEditor.\r
+               </p>\r
+       </div>\r
+       <div>\r
+               <label for="editor1">\r
+                       Inline editor:\r
+               </label>\r
+               <div id="editor1" contenteditable="true" style="padding: 5px 20px;">\r
+                       <p>This is some <strong>sample text</strong>. You are using <a href="http://ckeditor.com/">CKEditor</a>.</p>\r
+               </div>\r
+       </div>\r
+       <br>\r
+       <div>\r
+               <label for="editor2">\r
+                       Classic editor:\r
+               </label>\r
+               <textarea cols="80" id="editor2" name="editor2" rows="10">\r
+                       This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.\r
+               </textarea>\r
+       </div>\r
+       <script>\r
+\r
+               // We need to turn off the automatic editor creation first.\r
+               CKEDITOR.disableAutoInline = true;\r
+\r
+               var config = {\r
+                       toolbarGroups: [\r
+                               { name: 'mode' },\r
+                               { name: 'basicstyles' },\r
+                               { name: 'links' }\r
+                       ],\r
+                       extraPlugins: 'sourcedialog',\r
+                       removePlugins: 'sourcearea'\r
+               }\r
+\r
+               CKEDITOR.inline( 'editor1', config );\r
+               CKEDITOR.replace( 'editor2', config );\r
+\r
+       </script>\r
+       <div id="footer">\r
+               <hr>\r
+               <p>\r
+                       CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">\r
+                               http://ckeditor.com</a>\r
+               </p>\r
+               <p id="copy">\r
+                       Copyright &copy; 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a>\r
+                       - Frederico Knabben. All rights reserved.\r
+               </p>\r
+       </div>\r
+</body>\r
+</html>\r
index 97f23ef..7ecdefa 100644 (file)
@@ -2,4 +2,4 @@
 Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.md or http://ckeditor.com/license\r
 */\r
-.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}
\ No newline at end of file
+.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -600px !important;}.cke_rtl .cke_button__sourcedialog_icon, .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -624px !important;}.cke_ltr .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -648px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -648px !important;background-size: 16px !important;}
\ No newline at end of file
index b1a7853..ff104f1 100644 (file)
@@ -2,4 +2,4 @@
 Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.md or http://ckeditor.com/license\r
 */\r
-.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_bottom{padding-bottom:3px}.cke_combo_text{margin-bottom:-1px;margin-top:1px}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}
\ No newline at end of file
+.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_bottom{padding-bottom:3px}.cke_combo_text{margin-bottom:-1px;margin-top:1px}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -600px !important;}.cke_rtl .cke_button__sourcedialog_icon, .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -624px !important;}.cke_ltr .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -648px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -648px !important;background-size: 16px !important;}
\ No newline at end of file
index dc635b0..603df07 100644 (file)
@@ -2,4 +2,4 @@
 Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.md or http://ckeditor.com/license\r
 */\r
-.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}
\ No newline at end of file
+.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -600px !important;}.cke_rtl .cke_button__sourcedialog_icon, .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -624px !important;}.cke_ltr .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -648px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -648px !important;background-size: 16px !important;}
\ No newline at end of file
index 4e17b08..e4202f0 100644 (file)
@@ -2,4 +2,4 @@
 Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.md or http://ckeditor.com/license\r
 */\r
-.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_toolbox_collapser .cke_arrow{border-width:4px}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{border-width:3px}.cke_toolbox_collapser .cke_arrow{margin-top:0}.cke_toolbar{position:relative}.cke_rtl .cke_toolbar_end{right:auto;left:0}.cke_toolbar_end:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:1px;right:2px}.cke_rtl .cke_toolbar_end:after{right:auto;left:2px}.cke_hc .cke_toolbar_end:after{top:2px;right:5px;border-color:#000}.cke_hc.cke_rtl .cke_toolbar_end:after{right:auto;left:5px}.cke_combo+.cke_toolbar_end:after,.cke_toolbar.cke_toolbar_last .cke_toolbar_end:after{content:none;border:0}.cke_combo+.cke_toolgroup+.cke_toolbar_end:after{right:0}.cke_rtl .cke_combo+.cke_toolgroup+.cke_toolbar_end:after{right:auto;left:0}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}
\ No newline at end of file
+.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_toolbox_collapser .cke_arrow{border-width:4px}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{border-width:3px}.cke_toolbox_collapser .cke_arrow{margin-top:0}.cke_toolbar{position:relative}.cke_rtl .cke_toolbar_end{right:auto;left:0}.cke_toolbar_end:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:1px;right:2px}.cke_rtl .cke_toolbar_end:after{right:auto;left:2px}.cke_hc .cke_toolbar_end:after{top:2px;right:5px;border-color:#000}.cke_hc.cke_rtl .cke_toolbar_end:after{right:auto;left:5px}.cke_combo+.cke_toolbar_end:after,.cke_toolbar.cke_toolbar_last .cke_toolbar_end:after{content:none;border:0}.cke_combo+.cke_toolgroup+.cke_toolbar_end:after{right:0}.cke_rtl .cke_combo+.cke_toolgroup+.cke_toolbar_end:after{right:auto;left:0}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -600px !important;}.cke_rtl .cke_button__sourcedialog_icon, .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -624px !important;}.cke_ltr .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -648px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -648px !important;background-size: 16px !important;}
\ No newline at end of file
index a649668..d3bce52 100644 (file)
@@ -2,4 +2,4 @@
 Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.md or http://ckeditor.com/license\r
 */\r
-.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_top,.cke_contents,.cke_bottom{width:100%}.cke_button_arrow{font-size:0}.cke_rtl .cke_toolgroup,.cke_rtl .cke_toolbar_separator,.cke_rtl .cke_button,.cke_rtl .cke_button *,.cke_rtl .cke_combo,.cke_rtl .cke_combo *,.cke_rtl .cke_path_item,.cke_rtl .cke_path_item *,.cke_rtl .cke_path_empty{float:none}.cke_rtl .cke_toolgroup,.cke_rtl .cke_toolbar_separator,.cke_rtl .cke_combo_button,.cke_rtl .cke_combo_button *,.cke_rtl .cke_button,.cke_rtl .cke_button_icon{display:inline-block;vertical-align:top}.cke_rtl .cke_button_icon{float:none}.cke_resizer{width:10px}.cke_source{white-space:normal}.cke_bottom{position:static}.cke_colorbox{font-size:0}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}
\ No newline at end of file
+.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_top,.cke_contents,.cke_bottom{width:100%}.cke_button_arrow{font-size:0}.cke_rtl .cke_toolgroup,.cke_rtl .cke_toolbar_separator,.cke_rtl .cke_button,.cke_rtl .cke_button *,.cke_rtl .cke_combo,.cke_rtl .cke_combo *,.cke_rtl .cke_path_item,.cke_rtl .cke_path_item *,.cke_rtl .cke_path_empty{float:none}.cke_rtl .cke_toolgroup,.cke_rtl .cke_toolbar_separator,.cke_rtl .cke_combo_button,.cke_rtl .cke_combo_button *,.cke_rtl .cke_button,.cke_rtl .cke_button_icon{display:inline-block;vertical-align:top}.cke_rtl .cke_button_icon{float:none}.cke_resizer{width:10px}.cke_source{white-space:normal}.cke_bottom{position:static}.cke_colorbox{font-size:0}.cke_button__bold_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -0px !important;}.cke_button__italic_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -24px !important;}.cke_button__strike_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -48px !important;}.cke_button__subscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -72px !important;}.cke_button__superscript_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -96px !important;}.cke_button__underline_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -120px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -144px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -168px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -192px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -216px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -240px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -264px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -288px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -312px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -336px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -360px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -384px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -408px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -432px !important;}.cke_button__link_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -456px !important;}.cke_button__unlink_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -480px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -504px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -528px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -552px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -576px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -600px !important;}.cke_rtl .cke_button__sourcedialog_icon, .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -624px !important;}.cke_ltr .cke_button__sourcedialog_icon {background: url(icons.png?t=c9b79c9) no-repeat 0 -648px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon {background: url(icons_hidpi.png?t=c9b79c9) no-repeat 0 -648px !important;background-size: 16px !important;}
\ No newline at end of file
index e1e9e4a..ad22906 100644 (file)
Binary files a/js/ckeditor/skins/moono-lisa/icons.png and b/js/ckeditor/skins/moono-lisa/icons.png differ
index da3ef8d..7c76e52 100644 (file)
Binary files a/js/ckeditor/skins/moono-lisa/icons_hidpi.png and b/js/ckeditor/skins/moono-lisa/icons_hidpi.png differ
index b756217..2441aa1 100644 (file)
@@ -42,14 +42,17 @@ namespace('kivi.BankTransaction', function(ns) {
   };
 
   ns.create_invoice = function(bank_transaction_id) {
+    $.post('controller.pl?action=BankTransaction/create_invoice',
+           '&bt_id=' + bank_transaction_id + "&filter.bank_account=" + $('#filter_bank_account').val() + '&filter.fromdate=' + $('#filter_fromdate').val() + '&filter.todate=' + $('#filter_todate').val(),
+           kivi.eval_json_result);
+  };
+
+  ns.show_create_invoice_dialog = function(dialog_html) {
     kivi.popup_dialog({
-      url:    'controller.pl?action=BankTransaction/create_invoice',
-      data:   '&bt_id=' + bank_transaction_id + "&filter.bank_account=" + $('#filter_bank_account').val() + '&filter.fromdate=' + $('#filter_fromdate').val() + '&filter.todate=' + $('#filter_todate').val(),
-      type:   'POST',
+      html:    dialog_html,
       id:     'create_invoice_window',
       dialog: { title: kivi.t8('Create invoice') }
     });
-    return true;
   };
 
 
index e8cd923..02a2c2e 100644 (file)
@@ -21,6 +21,25 @@ namespace('kivi.CustomerVendor', function(ns) {
     });
   };
 
+  this.selectAdditionalBillingAddress = function(params) {
+    var additionalBillingAddressId = $('#additional_billing_address_id').val();
+    var url                        = 'controller.pl?action=CustomerVendor/ajaj_get_additional_billing_address&id='+ $('#cv_id').val() +'&db='+ $('#db').val() +'&additional_billing_address_id='+ additionalBillingAddressId;
+
+    $.getJSON(url, function(data) {
+      var additional_billing_address = data.additional_billing_address;
+      for (var key in additional_billing_address)
+        $('#additional_billing_address_'+ key).val(additional_billing_address[key])
+
+      if ( additionalBillingAddressId )
+        $('#action_delete_additional_billing_address').show();
+      else
+        $('#action_delete_additional_billing_address').hide();
+
+      if ( params.onFormSet )
+        params.onFormSet();
+    });
+  };
+
   this.selectDelivery = function(fromDate, toDate) {
     var deliveryId = $('#delivery_id').val();
 
@@ -449,7 +468,7 @@ namespace('kivi.CustomerVendor', function(ns) {
         $(elt).data('customer_vendor_picker', new kivi.CustomerVendor.Picker($(elt)));
     });
 
-    $('#cv_phone,#shipto_shiptophone,#contact_cp_phone1,#contact_cp_phone2,#contact_cp_mobile1,#contact_cp_mobile2').each(function(idx, elt) {
+    $('#cv_phone,#shipto_shiptophone,#additional_billing_address_phone,#contact_cp_phone1,#contact_cp_phone2,#contact_cp_mobile1,#contact_cp_mobile2').each(function(idx, elt) {
       kivi.CustomerVendor.init_dial_action($(elt));
     });
   }
diff --git a/js/kivi.DeliveryOrder.js b/js/kivi.DeliveryOrder.js
new file mode 100644 (file)
index 0000000..00a9294
--- /dev/null
@@ -0,0 +1,817 @@
+namespace('kivi.DeliveryOrder', function(ns) {
+  ns.check_cv = function() {
+    if ($('#type').val() == 'sales_delivery_order') {
+      if ($('#order_customer_id').val() === '') {
+        alert(kivi.t8('Please select a customer.'));
+        return false;
+      }
+    } else  {
+      if ($('#order_vendor_id').val() === '') {
+        alert(kivi.t8('Please select a vendor.'));
+        return false;
+      }
+    }
+    return true;
+  };
+
+  ns.check_duplicate_parts = function(question) {
+    var id_arr = $('[name="order.orderitems[].parts_id"]').map(function() { return this.value; }).get();
+
+    var i, obj = {}, pos = [];
+
+    for (i = 0; i < id_arr.length; i++) {
+      var id = id_arr[i];
+      if (obj.hasOwnProperty(id)) {
+        pos.push(i + 1);
+      }
+      obj[id] = 0;
+    }
+
+    if (pos.length > 0) {
+      question = question || kivi.t8("Do you really want to continue?");
+      return confirm(kivi.t8("There are duplicate parts at positions") + "\n"
+                     + pos.join(', ') + "\n"
+                     + question);
+    }
+    return true;
+  };
+
+  ns.check_valid_reqdate = function() {
+    if ($('#order_reqdate_as_date').val() === '') {
+      alert(kivi.t8('Please select a delivery date.'));
+      return false;
+    } else {
+      return true;
+    }
+  };
+
+  ns.save = function(action, warn_on_duplicates, warn_on_reqdate) {
+    if (!ns.check_cv()) return;
+    if (warn_on_duplicates && !ns.check_duplicate_parts()) return;
+    if (warn_on_reqdate    && !ns.check_valid_reqdate())   return;
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'DeliveryOrder/' + action });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.delete_order = function() {
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'DeliveryOrder/delete' });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.show_print_options = function(warn_on_duplicates, warn_on_reqdate) {
+    if (!ns.check_cv()) return;
+    if (warn_on_duplicates && !ns.check_duplicate_parts(kivi.t8("Do you really want to print?"))) return;
+    if (warn_on_reqdate    && !ns.check_valid_reqdate())   return;
+
+    kivi.popup_dialog({
+      id: 'print_options',
+      dialog: {
+        title: kivi.t8('Print options'),
+        width:  800,
+        height: 300
+      }
+    });
+  };
+
+  ns.open_stock_in_out_dialog = function(clicked, in_out) {
+    var $row = $(clicked).parents("tbody").first();
+    var id = $row.find('[name="orderitem_ids[+]"]').val();
+    $row.uniqueId();
+
+    kivi.popup_dialog({
+      id: "stock_in_out_dialog",
+      url: "controller.pl?action=DeliveryOrder/stock_in_out_dialog",
+      data: {
+        id:            $("#id").val(),
+        type:          $("#type").val(),
+        parts_id:      $row.find("[name$=parts_id]").val(),
+        unit:          $row.find("[name$=unit]").val(),
+        qty_as_number: $row.find("[name$=qty_as_number]").val(),
+        stock:         $row.find("[name$=stock_info]").val(),
+        item_id:       id,
+        row:           $row.attr("id"),
+      },
+      dialog: { title: kivi.t8('Transfer stock') }
+    });
+  };
+
+  ns.save_updated_stock = function() {
+    // stock information is saved in DOM as a yaml dump.
+    // we don't want to do this in javascript so we do a tiny roundtrip to the backend
+
+    let data = [];
+    $("#stock-in-out-table tr.listrow").each((i,row) => {
+      let qty = kivi.parse_amount($(row).find(".data-qty").val());
+
+      if (qty === 0) return;
+
+      data.push({
+        qty:                           qty,
+        warehouse_id:                  $(row).find(".data-warehouse-id").val(),
+        bin_id:                        $(row).find(".data-bin-id").val(),
+        chargenumber:                  $(row).find(".data-chargenumber").val(),
+        bestbefore:                    $(row).find(".data-bestbefore").val(),
+        unit:                          $(row).find(".data-unit").val(),
+        delivery_order_items_stock_id: $(row).find(".data-stock-id").val(),
+      });
+    });
+
+    let row = $(".data-row").val();
+
+    $.post("controller.pl",
+      kivi.serialize({
+        action:     "DeliveryOrder/update_stock_information",
+        unit:       $("#" + row).find("[name$=unit]").val(),
+        stock_info: data,
+        row:        row
+      }),
+      (data) => {
+        $("#" + row + " .data-stock-info").val(data.stock_info);
+        $("#" + row + " .data-stock-qty").text(data.stock_qty)
+        $("#stock_in_out_dialog").dialog("close");
+      }
+    );
+  };
+
+  ns.print = function() {
+    $('#print_options').dialog('close');
+
+    var data = $('#order_form').serializeArray();
+    data = data.concat($('#print_options_form').serializeArray());
+    data.push({ name: 'action', value: 'DeliveryOrder/print' });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  var email_dialog;
+
+  ns.setup_send_email_dialog = function() {
+    kivi.SalesPurchase.show_all_print_options_elements();
+    kivi.SalesPurchase.show_print_options_elements([ 'sendmode', 'media', 'copies', 'remove_draft' ], false);
+
+    $('#print_options_form table').first().remove().appendTo('#email_form_print_options');
+
+    var to_focus = $('#email_form_to').val() === '' ? 'to' : 'subject';
+    $('#email_form_' + to_focus).focus();
+  };
+
+  ns.finish_send_email_dialog = function() {
+    kivi.SalesPurchase.show_all_print_options_elements();
+
+    $('#email_form_print_options table').first().remove().prependTo('#print_options_form');
+    return true;
+  };
+
+  ns.show_email_dialog = function(html) {
+    var id            = 'send_email_dialog';
+    var dialog_params = {
+      id:     id,
+      width:  800,
+      height: 600,
+      title:  kivi.t8('Send email'),
+      modal:  true,
+      beforeClose: kivi.DeliveryOrder.finish_send_email_dialog,
+      close: function(event, ui) {
+        email_dialog.remove();
+      }
+    };
+
+    $('#' + id).remove();
+
+    email_dialog = $('<div style="display:none" id="' + id + '"></div>').appendTo('body');
+    email_dialog.html(html);
+    email_dialog.dialog(dialog_params);
+
+    kivi.DeliveryOrder.setup_send_email_dialog();
+
+    $('.cancel').click(ns.close_email_dialog);
+
+    return true;
+  };
+
+  ns.send_email = function() {
+    // push button only once -> slow response from mail server
+    ns.email_dialog_disable_send();
+
+    var data = $('#order_form').serializeArray();
+    data = data.concat($('[name^="email_form."]').serializeArray());
+    data = data.concat($('[name^="print_options."]').serializeArray());
+    data.push({ name: 'action', value: 'DeliveryOrder/send_email' });
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.email_dialog_disable_send = function() {
+    // disable mail send event to prevent
+    // impatient users to send multiple times
+    $('#send_email').prop('disabled', true);
+  };
+
+  ns.close_email_dialog = function() {
+    email_dialog.dialog("close");
+  };
+
+  ns.set_number_in_title = function(elt) {
+    $('#nr_in_title').html($(elt).val());
+  };
+
+  ns.reload_cv_dependent_selections = function() {
+    $('#order_shipto_id').val('');
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'DeliveryOrder/customer_vendor_changed' });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.reformat_number = function(event) {
+    $(event.target).val(kivi.format_amount(kivi.parse_amount($(event.target).val()), -2));
+  };
+
+  ns.reformat_number_as_null_number = function(event) {
+    if ($(event.target).val() === '') {
+      return;
+    }
+    ns.reformat_number(event);
+  };
+
+  ns.update_exchangerate = function(event) {
+    if (!ns.check_cv()) {
+      $('#order_currency_id').val($('#old_currency_id').val());
+      return;
+    }
+
+    var rate_input = $('#order_exchangerate_as_null_number');
+    // unset exchangerate if currency changed
+    if ($('#order_currency_id').val() !== $('#old_currency_id').val()) {
+      rate_input.val('');
+    }
+
+    // only set exchangerate if unset
+    if (rate_input.val() !== '') {
+      return;
+    }
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'DeliveryOrder/update_exchangerate' });
+
+    $.ajax({
+      url: 'controller.pl',
+      data: data,
+      method: 'POST',
+      dataType: 'json',
+      success: function(data){
+        if (!data.is_standard) {
+          $('#currency_name').text(data.currency_name);
+          if (data.exchangerate) {
+            rate_input.val(data.exchangerate);
+          } else {
+            rate_input.val('');
+          }
+          $('#exchangerate_settings').show();
+        } else {
+          rate_input.val('');
+          $('#exchangerate_settings').hide();
+        }
+        if ($('#order_currency_id').val() != $('#old_currency_id').val() ||
+            !data.is_standard && data.exchangerate != $('#old_exchangerate').val()) {
+          kivi.display_flash('warning', kivi.t8('You have changed the currency or exchange rate. Please check prices.'));
+        }
+        $('#old_currency_id').val($('#order_currency_id').val());
+        $('#old_exchangerate').val(data.exchangerate);
+      }
+    });
+  };
+
+  ns.exchangerate_changed = function(event) {
+    if (kivi.parse_amount($('#order_exchangerate_as_null_number').val()) != kivi.parse_amount($('#old_exchangerate').val())) {
+      kivi.display_flash('warning', kivi.t8('You have changed the currency or exchange rate. Please check prices.'));
+      $('#old_exchangerate').val($('#order_exchangerate_as_null_number').val());
+    }
+  };
+
+  ns.unit_change = function(event) {
+    var row           = $(event.target).parents("tbody").first();
+    var item_id_dom   = $(row).find('[name="orderitem_ids[+]"]');
+    var sellprice_dom = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
+    var select_elt    = $(row).find('[name="order.orderitems[].unit"]');
+
+    var oldval = $(select_elt).data('oldval');
+    $(select_elt).data('oldval', $(select_elt).val());
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action',           value: 'DeliveryOrder/unit_changed'     },
+              { name: 'item_id',          value: item_id_dom.val()        },
+              { name: 'old_unit',         value: oldval                   },
+              { name: 'sellprice_dom_id', value: sellprice_dom.attr('id') });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.update_sellprice = function(item_id, price_str) {
+    var row       = $('#item_' + item_id).parents("tbody").first();
+    var price_elt = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
+    var html_elt  = $(row).find('[name="sellprice_text"]');
+    price_elt.val(price_str);
+    html_elt.html(price_str);
+  };
+
+  ns.load_second_row = function(row) {
+    var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
+    var div_elt     = $(row).find('[name="second_row"]');
+
+    if ($(div_elt).data('loaded') == 1) {
+      return;
+    }
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action',     value: 'DeliveryOrder/load_second_rows' },
+              { name: 'item_ids[]', value: item_id_dom.val()        });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.load_all_second_rows = function() {
+    var rows = $('.row_entry').filter(function(idx, elt) {
+      return $(elt).find('[name="second_row"]').data('loaded') != 1;
+    });
+
+    var item_ids = $.map(rows, function(elt) {
+      var item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
+      return { name: 'item_ids[]', value: item_id };
+    });
+
+    if (item_ids.length == 0) {
+      return;
+    }
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'DeliveryOrder/load_second_rows' });
+    data = data.concat(item_ids);
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.hide_second_row = function(row) {
+    $(row).children().not(':first').hide();
+    $(row).data('expanded', 0);
+    var elt = $(row).find('.expand');
+    elt.attr('src', "image/expand.svg");
+    elt.attr('alt', kivi.t8('Show details'));
+    elt.attr('title', kivi.t8('Show details'));
+  };
+
+  ns.show_second_row = function(row) {
+    $(row).children().not(':first').show();
+    $(row).data('expanded', 1);
+    var elt = $(row).find('.expand');
+    elt.attr('src', "image/collapse.svg");
+    elt.attr('alt', kivi.t8('Hide details'));
+    elt.attr('title', kivi.t8('Hide details'));
+  };
+
+  ns.toggle_second_row = function(row) {
+    if ($(row).data('expanded') == 1) {
+      ns.hide_second_row(row);
+    } else {
+      ns.show_second_row(row);
+    }
+  };
+
+  ns.init_row_handlers = function() {
+    kivi.run_once_for('.reformat_number', 'on_change_reformat', function(elt) {
+      $(elt).change(ns.reformat_number);
+    });
+
+    kivi.run_once_for('.unitselect', 'on_change_unit_with_oldval', function(elt) {
+      $(elt).data('oldval', $(elt).val());
+      $(elt).change(ns.unit_change);
+    });
+
+    kivi.run_once_for('.row_entry', 'on_kbd_click_show_hide', function(elt) {
+      $(elt).keydown(function(event) {
+        var row;
+        if (event.keyCode == 40 && event.shiftKey === true) {
+          // shift arrow down
+          event.preventDefault();
+          row = $(event.target).parents(".row_entry").first();
+          ns.load_second_row(row);
+          ns.show_second_row(row);
+          return false;
+        }
+        if (event.keyCode == 38 && event.shiftKey === true) {
+          // shift arrow up
+          event.preventDefault();
+          row = $(event.target).parents(".row_entry").first();
+          ns.hide_second_row(row);
+          return false;
+        }
+      });
+    });
+
+    kivi.run_once_for('.expand', 'expand_second_row', function(elt) {
+      $(elt).click(function(event) {
+        event.preventDefault();
+        var row = $(event.target).parents(".row_entry").first();
+        ns.load_second_row(row);
+        ns.toggle_second_row(row);
+        return false;
+      })
+    });
+
+  };
+
+  ns.redisplay_line_values = function(is_sales, data) {
+    $('.row_entry').each(function(idx, elt) {
+      $(elt).find('[name="linetotal"]').html(data[idx][0]);
+      if (is_sales && $(elt).find('[name="second_row"]').data('loaded') == 1) {
+        var mt = data[idx][1];
+        var mp = data[idx][2];
+        var h  = '<span';
+        if (mt[0] === '-') h += ' class="plus0"';
+        h += '>' + mt + '&nbsp;&nbsp;' + mp + '%';
+        h += '</span>';
+        $(elt).find('[name="linemargin"]').html(h);
+      }
+    });
+  };
+
+  ns.redisplay_cvpartnumbers = function(data) {
+    $('.row_entry').each(function(idx, elt) {
+      $(elt).find('[name="cvpartnumber"]').html(data[idx][0]);
+    });
+  };
+
+  ns.renumber_positions = function() {
+    $('.row_entry [name="position"]').each(function(idx, elt) {
+      $(elt).html(idx+1);
+    });
+    $('.row_entry').each(function(idx, elt) {
+      $(elt).data("position", idx+1);
+    });
+  };
+
+  ns.reorder_items = function(order_by) {
+    var dir = $('#' + order_by + '_header_id a img').attr("data-sort-dir");
+    $('#row_table_id thead a img').remove();
+
+    var src;
+    if (dir == "1") {
+      dir = "0";
+      src = "image/up.png";
+    } else {
+      dir = "1";
+      src = "image/down.png";
+    }
+
+    $('#' + order_by + '_header_id a').append('<img border=0 data-sort-dir=' + dir + ' src=' + src + ' alt="' + kivi.t8('sort items') + '">');
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action',   value: 'DeliveryOrder/reorder_items' },
+              { name: 'order_by', value: order_by              },
+              { name: 'sort_dir', value: dir                   });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.redisplay_items = function(data) {
+    var old_rows = $('.row_entry').detach();
+    var new_rows = [];
+    $(data).each(function(idx, elt) {
+      new_rows.push(old_rows[elt.old_pos - 1]);
+    });
+    $(new_rows).appendTo($('#row_table_id'));
+    ns.renumber_positions();
+  };
+
+  ns.get_insert_before_item_id = function(wanted_pos) {
+    if (wanted_pos === '') return;
+
+    var insert_before_item_id;
+    // selection by data does not seem to work if data is changed at runtime
+    // var elt = $('.row_entry [data-position="' + wanted_pos + '"]');
+    $('.row_entry').each(function(idx, elt) {
+      if ($(elt).data("position") == wanted_pos) {
+        insert_before_item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
+        return false;
+      }
+    });
+
+    return insert_before_item_id;
+  };
+
+  ns.add_item = function() {
+    if ($('#add_item_parts_id').val() === '') return;
+    if (!ns.check_cv()) return;
+
+    $('#row_table_id thead a img').remove();
+
+    var insert_before_item_id = ns.get_insert_before_item_id($('#add_item_position').val());
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'DeliveryOrder/add_item' },
+              { name: 'insert_before_item_id', value: insert_before_item_id });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.open_multi_items_dialog = function() {
+    if (!ns.check_cv()) return;
+
+    var pp = $("#add_item_parts_id").data("part_picker");
+    pp.o.multiple=1;
+    pp.open_dialog();
+  };
+
+  ns.add_multi_items = function(data) {
+    var insert_before_item_id = ns.get_insert_before_item_id($('#multi_items_position').val());
+    data = data.concat($('#order_form').serializeArray());
+    data.push({ name: 'action', value: 'DeliveryOrder/add_multi_items' },
+              { name: 'insert_before_item_id', value: insert_before_item_id });
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.delete_order_item_row = function(clicked) {
+    var row = $(clicked).parents("tbody").first();
+    $(row).remove();
+
+    ns.renumber_positions();
+  };
+
+  ns.row_table_scroll_down = function() {
+    $('#row_table_scroll_id').scrollTop($('#row_table_scroll_id')[0].scrollHeight);
+  };
+
+  ns.show_longdescription_dialog = function(clicked) {
+    var row                 = $(clicked).parents("tbody").first();
+    var position            = $(row).find('[name="position"]').html();
+    var partnumber          = $(row).find('[name="partnumber"]').html();
+    var description_elt     = $(row).find('[name="order.orderitems[].description"]');
+    var longdescription_elt = $(row).find('[name="order.orderitems[].longdescription"]');
+
+    var params = {
+      runningnumber:           position,
+      partnumber:              partnumber,
+      description:             description_elt.val(),
+      default_longdescription: longdescription_elt.val(),
+      set_function:            function(val) {
+        longdescription_elt.val(val);
+      }
+    };
+
+    kivi.SalesPurchase.edit_longdescription_with_params(params);
+  };
+
+  ns.price_chooser_item_row = function(clicked) {
+    if (!ns.check_cv()) return;
+    var row         = $(clicked).parents("tbody").first();
+    var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action',  value: 'DeliveryOrder/price_popup' },
+              { name: 'item_id', value: item_id_dom.val()   });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.show_vc_details_dialog = function() {
+    if (!ns.check_cv()) return;
+    var vc;
+    var vc_id;
+    var title;
+    if ($('#order_customer_id').val()) {
+      vc    = 'customer';
+      vc_id = $('#order_customer_id').val();
+      title = kivi.t8('Customer details');
+    } else {
+      vc    = 'vendor';
+      vc_id = $('#order_vendor_id').val();
+      title = kivi.t8('Vendor details');
+    }
+
+    kivi.popup_dialog({
+      url:    'controller.pl',
+      data:   { action: 'DeliveryOrder/show_customer_vendor_details_dialog',
+                type  : $('#type').val(),
+                vc    : vc,
+                vc_id : vc_id
+              },
+      id:     'jq_customer_vendor_details_dialog',
+      dialog: {
+        title:  title,
+        width:  800,
+        height: 650
+      }
+    });
+    return true;
+  };
+
+  ns.update_row_from_master_data = function(clicked) {
+    var row = $(clicked).parents("tbody").first();
+    var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'DeliveryOrder/update_row_from_master_data' });
+    data.push({ name: 'item_ids[]', value: item_id_dom.val() });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.update_all_rows_from_master_data = function() {
+    var item_ids = $.map($('.row_entry'), function(elt) {
+      var item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
+      return { name: 'item_ids[]', value: item_id };
+    });
+
+    if (item_ids.length == 0) {
+      return;
+    }
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'DeliveryOrder/update_row_from_master_data' });
+    data = data.concat(item_ids);
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.show_calculate_qty_dialog = function(clicked) {
+    var row        = $(clicked).parents("tbody").first();
+    var input_id   = $(row).find('[name="order.orderitems[].qty_as_number"]').attr('id');
+    var formula_id = $(row).find('[name="formula[+]"]').attr('id');
+
+    calculate_qty_selection_dialog("", input_id, "", formula_id);
+    return true;
+  };
+
+  ns.edit_custom_shipto = function() {
+    if (!ns.check_cv()) return;
+
+    kivi.SalesPurchase.edit_custom_shipto();
+  };
+
+  ns.purchase_order_check_for_direct_delivery = function() {
+    if ($('#type').val() != 'sales_order') {
+      kivi.submit_form_with_action($('#order_form'), 'DeliveryOrder/purchase_order');
+    }
+
+    var empty = true;
+    var shipto;
+    if ($('#order_shipto_id').val() !== '') {
+      empty = false;
+      shipto = $('#order_shipto_id option:selected').text();
+    } else {
+      $('#shipto_inputs [id^="shipto"]').each(function(idx, elt) {
+        if (!empty)                                     return true;
+        if (/^shipto_to_copy/.test($(elt).prop('id')))  return true;
+        if (/^shiptocp_gender/.test($(elt).prop('id'))) return true;
+        if (/^shiptocvar_/.test($(elt).prop('id')))     return true;
+        if ($(elt).val() !== '') {
+          empty = false;
+          return false;
+        }
+      });
+      var shipto_elements = [];
+      $([$('#shiptoname').val(), $('#shiptostreet').val(), $('#shiptozipcode').val(), $('#shiptocity').val()]).each(function(idx, elt) {
+        if (elt !== '') shipto_elements.push(elt);
+      });
+      shipto = shipto_elements.join('; ');
+    }
+
+    var use_it = false;
+    if (!empty) {
+      ns.direct_delivery_dialog(shipto);
+    } else {
+      kivi.submit_form_with_action($('#order_form'), 'DeliveryOrder/purchase_order');
+    }
+  };
+
+  ns.direct_delivery_callback = function(accepted) {
+    $('#direct-delivery-dialog').dialog('close');
+
+    if (accepted) {
+      $('<input type="hidden" name="use_shipto">').appendTo('#order_form').val('1');
+    }
+
+    kivi.submit_form_with_action($('#order_form'), 'DeliveryOrder/purchase_order');
+  };
+
+  ns.direct_delivery_dialog = function(shipto) {
+    $('#direct-delivery-dialog').remove();
+
+    var text1 = kivi.t8('You have entered or selected the following shipping address for this customer:');
+    var text2 = kivi.t8('Do you want to carry this shipping address over to the new purchase order so that the vendor can deliver the goods directly to your customer?');
+    var html  = '<div id="direct-delivery-dialog"><p>' + text1 + '</p><p>' + shipto + '</p><p>' + text2 + '</p>';
+    html      = html + '<hr><p>';
+    html      = html + '<input type="button" value="' + kivi.t8('Yes') + '" size="30" onclick="kivi.DeliveryOrder.direct_delivery_callback(true)">';
+    html      = html + '&nbsp;';
+    html      = html + '<input type="button" value="' + kivi.t8('No')  + '" size="30" onclick="kivi.DeliveryOrder.direct_delivery_callback(false)">';
+    html      = html + '</p></div>';
+    $(html).hide().appendTo('#order_form');
+
+    kivi.popup_dialog({id: 'direct-delivery-dialog',
+                       dialog: {title:  kivi.t8('Carry over shipping address'),
+                                height: 300,
+                                width:  500 }});
+  };
+
+  ns.follow_up_window = function() {
+    var id   = $('#id').val();
+    var type = $('#type').val();
+
+    var number_info = '';
+    if ($('#type').val() == 'sales_order' || $('#type').val() == 'purchase_order') {
+      number_info = $('#order_ordnumber').val();
+    } else if ($('#type').val() == 'sales_quotation' || $('#type').val() == 'request_quotation') {
+      number_info = $('#order_quonumber').val();
+    }
+
+    var name_info = '';
+    if ($('#type').val() == 'sales_order' || $('#type').val() == 'sales_quotation') {
+      name_info = $('#order_customer_id_name').val();
+    } else if ($('#type').val() == 'purchase_order' || $('#type').val() == 'request_quotation') {
+      name_info = $('#order_vendor_id_name').val();
+    }
+
+    var info = '';
+    if (number_info !== '') { info += ' (' + number_info + ')' }
+    if (name_info   !== '') { info += ' (' + name_info + ')' }
+
+    if (!$('#follow_up_rowcount').lenght) {
+      $('<input type="hidden" name="follow_up_rowcount"        id="follow_up_rowcount">').appendTo('#order_form');
+      $('<input type="hidden" name="follow_up_trans_id_1"      id="follow_up_trans_id_1">').appendTo('#order_form');
+      $('<input type="hidden" name="follow_up_trans_type_1"    id="follow_up_trans_type_1">').appendTo('#order_form');
+      $('<input type="hidden" name="follow_up_trans_info_1"    id="follow_up_trans_info_1">').appendTo('#order_form');
+      $('<input type="hidden" name="follow_up_trans_subject_1" id="follow_up_trans_subject_1">').appendTo('#order_form');
+    }
+    $('#follow_up_rowcount').val(1);
+    $('#follow_up_trans_id_1').val(id);
+    $('#follow_up_trans_type_1').val(type);
+    $('#follow_up_trans_info_1').val(info);
+    $('#follow_up_trans_subject_1').val($('#order_transaction_description').val());
+
+    follow_up_window();
+  };
+
+  ns.create_part = function() {
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'DeliveryOrder/create_part' });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+});
+
+$(function() {
+  $('#order_customer_id').change(kivi.DeliveryOrder.reload_cv_dependent_selections);
+  $('#order_vendor_id').change(kivi.DeliveryOrder.reload_cv_dependent_selections);
+
+  $('#order_currency_id').change(kivi.DeliveryOrder.update_exchangerate);
+  $('#order_transdate_as_date').change(kivi.DeliveryOrder.update_exchangerate);
+  $('#order_exchangerate_as_null_number').change(kivi.DeliveryOrder.exchangerate_changed);
+
+  $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_description').val(o.description) });
+  $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_unit').val(o.unit) });
+
+  $('.add_item_input').keydown(function(event) {
+    if (event.keyCode == 13) {
+      event.preventDefault();
+      kivi.DeliveryOrder.add_item();
+      return false;
+    }
+  });
+
+  kivi.DeliveryOrder.init_row_handlers();
+
+  $('#row_table_id').on('sortstop', function(event, ui) {
+    $('#row_table_id thead a img').remove();
+    kivi.DeliveryOrder.renumber_positions();
+  });
+
+  $('#expand_all').on('click', function(event) {
+    event.preventDefault();
+    if ($('#expand_all').data('expanded') == 1) {
+      $('#expand_all').data('expanded', 0);
+      $('#expand_all').attr('src', 'image/expand.svg');
+      $('#expand_all').attr('alt', kivi.t8('Show all details'));
+      $('#expand_all').attr('title', kivi.t8('Show all details'));
+      $('.row_entry').each(function(idx, elt) {
+        kivi.DeliveryOrder.hide_second_row(elt);
+      });
+    } else {
+      $('#expand_all').data('expanded', 1);
+      $('#expand_all').attr('src', "image/collapse.svg");
+      $('#expand_all').attr('alt', kivi.t8('Hide all details'));
+      $('#expand_all').attr('title', kivi.t8('Hide all details'));
+      kivi.DeliveryOrder.load_all_second_rows();
+      $('.row_entry').each(function(idx, elt) {
+        kivi.DeliveryOrder.show_second_row(elt);
+      });
+    }
+    return false;
+  });
+
+  $('.reformat_number_as_null_number').change(kivi.DeliveryOrder.reformat_number_as_null_number);
+
+});
index 63a8534..55aa4ea 100644 (file)
@@ -409,4 +409,16 @@ namespace('kivi.File', function(ns) {
     });
   };
 
+  ns.toggle_versions = function(file_id) {
+    if ($('#version_toggle_' + file_id).data('versions_expanded')) {
+      $('.version_row_'    + file_id).hide();
+      $('#version_toggle_' + file_id).data('versions_expanded', 0);
+      $('#version_toggle_' + file_id).html("⏷ ");
+    } else {
+      $('.version_row_'    + file_id).show();
+      $('#version_toggle_' + file_id).data('versions_expanded', 1);
+      $('#version_toggle_' + file_id).html("⏶ ");
+    }
+  };
+
 });
index a96f49f..9ef6ef5 100644 (file)
@@ -45,7 +45,7 @@ namespace('kivi.Order', function(ns) {
     }
   };
 
-  ns.save = function(action, warn_on_duplicates, warn_on_reqdate) {
+  ns.save = function(action, warn_on_duplicates, warn_on_reqdate, back_to_caller) {
     if (!ns.check_cv()) return;
     if (warn_on_duplicates && !ns.check_duplicate_parts()) return;
     if (warn_on_reqdate    && !ns.check_valid_reqdate())   return;
@@ -53,6 +53,8 @@ namespace('kivi.Order', function(ns) {
     var data = $('#order_form').serializeArray();
     data.push({ name: 'action', value: 'Order/' + action });
 
+    if (back_to_caller) data.push({ name: 'back_to_caller', value: '1' });
+
     $.post("controller.pl", data, kivi.eval_json_result);
   };
 
@@ -96,6 +98,9 @@ namespace('kivi.Order', function(ns) {
 
     $('#print_options_form table').first().remove().appendTo('#email_form_print_options');
 
+    $('select#format').change(kivi.Order.adjust_email_attachment_name_for_template_format);
+    kivi.Order.adjust_email_attachment_name_for_template_format();
+
     var to_focus = $('#email_form_to').val() === '' ? 'to' : 'subject';
     $('#email_form_' + to_focus).focus();
   };
@@ -155,6 +160,20 @@ namespace('kivi.Order', function(ns) {
     email_dialog.dialog("close");
   };
 
+  ns.adjust_email_attachment_name_for_template_format = function() {
+    var $filename_elt = $('#email_form_attachment_filename');
+    var $format_elt   = $('select#format');
+
+    if (!$filename_elt || !$format_elt)
+      return;
+
+    var format   = $format_elt.val().toLowerCase();
+    var new_ext  = format == 'html' ? 'html' : format == 'opendocument' ? 'odt' : 'pdf';
+    var filename = $filename_elt.val();
+
+    $filename_elt.val(filename.replace(/[^.]+$/, new_ext));
+  };
+
   ns.set_number_in_title = function(elt) {
     $('#nr_in_title').html($(elt).val());
   };
@@ -234,6 +253,8 @@ namespace('kivi.Order', function(ns) {
   };
 
   ns.recalc_amounts_and_taxes = function() {
+    if (!kivi.validate_form('#order_form')) return;
+
     var data = $('#order_form').serializeArray();
     data.push({ name: 'action', value: 'Order/recalc_amounts_and_taxes' });
 
@@ -453,6 +474,15 @@ namespace('kivi.Order', function(ns) {
     return insert_before_item_id;
   };
 
+  ns.update_item_input_row = function() {
+    if (!ns.check_cv()) return;
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'Order/update_item_input_row' });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
   ns.add_item = function() {
     if ($('#add_item_parts_id').val() === '') return;
     if (!ns.check_cv()) return;
@@ -528,7 +558,7 @@ namespace('kivi.Order', function(ns) {
     $.post("controller.pl", data, kivi.eval_json_result);
   };
 
-  ns.update_price_source = function(item_id, source, descr, price_str, price_editable) {
+  ns.set_price_and_source_text = function(item_id, source, descr, price_str, price_editable) {
     var row        = $('#item_' + item_id).parents("tbody").first();
     var source_elt = $(row).find('[name="order.orderitems[].active_price_source"]');
     var button_elt = $(row).find('[name="price_chooser_button"]');
@@ -557,13 +587,17 @@ namespace('kivi.Order', function(ns) {
       var html_elt  = $(row).find('[name="sellprice_text"]');
       price_elt.val(price_str);
       html_elt.html(price_str);
-      ns.recalc_amounts_and_taxes();
     }
+  };
 
+  ns.update_price_source = function(item_id, source, descr, price_str, price_editable) {
+    ns.set_price_and_source_text(item_id, source, descr, price_str, price_editable);
+
+    if (price_str) ns.recalc_amounts_and_taxes();
     kivi.io.close_dialog();
   };
 
-  ns.update_discount_source = function(item_id, source, descr, discount_str, price_editable) {
+  ns.set_discount_and_source_text = function(item_id, source, descr, discount_str, price_editable) {
     var row        = $('#item_' + item_id).parents("tbody").first();
     var source_elt = $(row).find('[name="order.orderitems[].active_discount_source"]');
     var button_elt = $(row).find('[name="price_chooser_button"]');
@@ -592,9 +626,13 @@ namespace('kivi.Order', function(ns) {
       var html_elt     = $(row).find('[name="discount_text"]');
       discount_elt.val(discount_str);
       html_elt.html(discount_str);
-      ns.recalc_amounts_and_taxes();
     }
+  };
+
+  ns.update_discount_source = function(item_id, source, descr, discount_str, price_editable) {
+    ns.set_discount_and_source_text(item_id, source, descr, discount_str, price_editable);
 
+    if (discount_str) ns.recalc_amounts_and_taxes();
     kivi.io.close_dialog();
   };
 
@@ -821,7 +859,7 @@ namespace('kivi.Order', function(ns) {
     if (number_info !== '') { info += ' (' + number_info + ')' }
     if (name_info   !== '') { info += ' (' + name_info + ')' }
 
-    if (!$('#follow_up_rowcount').lenght) {
+    if (!$('#follow_up_rowcount').length) {
       $('<input type="hidden" name="follow_up_rowcount"        id="follow_up_rowcount">').appendTo('#order_form');
       $('<input type="hidden" name="follow_up_trans_id_1"      id="follow_up_trans_id_1">').appendTo('#order_form');
       $('<input type="hidden" name="follow_up_trans_type_1"    id="follow_up_trans_type_1">').appendTo('#order_form');
@@ -840,6 +878,61 @@ namespace('kivi.Order', function(ns) {
   ns.create_part = function() {
     var data = $('#order_form').serializeArray();
     data.push({ name: 'action', value: 'Order/create_part' });
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.check_transport_cost_article_presence = function() {
+    var $form          = $('#order_form');
+    var wanted_part_id = $form.data('transport-cost-reminder-article-id');
+
+    if (!wanted_part_id) return true
+
+    var id_arr = $('[name="order.orderitems[].parts_id"]').map(function() { return this.value; }).get();
+    id_arr = $.grep(id_arr, function(elt) {
+      return ((elt*1) === wanted_part_id);
+    });
+
+    if (id_arr.length) return true;
+
+    var description = $form.data('transport-cost-reminder-article-description');
+    return confirm(kivi.t8("The transport cost article '#1' is missing. Do you want to continue anyway?", [ description ]));
+  };
+
+  ns.check_cusordnumber_presence = function() {
+    if ($('#order_cusordnumber').val() === '') {
+      return confirm(kivi.t8('The customer order number is missing. Do you want to continue anyway?'));
+    }
+    return true;
+  };
+
+  ns.load_phone_note = function(id, subject, body) {
+    $('#phone_note_edit_text').html(kivi.t8('Edit note'));
+    $('#phone_note_id').val(id);
+    $('#phone_note_subject').val(subject);
+    $('#phone_note_body').val(body);
+    $('#phone_note_delete_button').show();
+  };
+
+  ns.cancel_phone_note = function() {
+    $('#phone_note_edit_text').html(kivi.t8('Add note'));
+    $('#phone_note_id').val('');
+    $('#phone_note_subject').val('');
+    $('#phone_note_body').val('');
+    $('#phone_note_delete_button').hide();
+  };
+
+  ns.save_phone_note = function() {
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'Order/save_phone_note' });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.delete_phone_note = function() {
+    if ($('#phone_note_id').val() === '') return;
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'Order/delete_phone_note' });
 
     $.post("controller.pl", data, kivi.eval_json_result);
   };
@@ -857,13 +950,9 @@ $(function() {
   $('#order_transdate_as_date').change(kivi.Order.update_exchangerate);
   $('#order_exchangerate_as_null_number').change(kivi.Order.exchangerate_changed);
 
-  if ($('#type').val() == 'sales_order' || $('#type').val() == 'sales_quotation' ) {
-    $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) });
-  } else {
-    $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.lastcost, -2)) });
-  }
-  $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_description').val(o.description) });
-  $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_unit').val(o.unit) });
+  $('#add_item_parts_id').on('set_item:PartPicker', function() {
+    kivi.Order.update_item_input_row();
+  });
 
   $('.add_item_input').keydown(function(event) {
     if (event.keyCode == 13) {
index c287cf0..3451b7f 100644 (file)
@@ -36,7 +36,7 @@ namespace('kivi', function(k){
         send_query('select_autocomplete', undefined, ui.item.id, kivi.eval_json_result);
       },
     });
-    $real.keydown(function(event){
+    $real.keypress(function(event){
       if (event.which == KEY.ENTER) {
         if ($real.val() !== '') {
           submit_search($real.val());
index 98a538c..4dc390b 100644 (file)
@@ -1,4 +1,6 @@
 namespace('kivi.SalesPurchase', function(ns) {
+  this.longdescription_dialog_size_percentage = 0;
+
   this.edit_longdescription = function(row) {
     var $element = $('#longdescription_' + row);
 
@@ -17,8 +19,20 @@ namespace('kivi.SalesPurchase', function(ns) {
   };
 
   this.edit_longdescription_with_params = function(params) {
+    var dialog_width    = 800;
+    var dialog_height   = 500;
+    var textarea_width  = 750;
+    var textarea_height = 220;
+    if (this.longdescription_dialog_size_percentage != 0) {
+      dialog_width    = Math.ceil(window.innerWidth  * this.longdescription_dialog_size_percentage/100);
+      dialog_height   = Math.ceil(window.innerHeight * this.longdescription_dialog_size_percentage/100);
+      textarea_width  = Math.ceil(dialog_width * 95/100);
+      textarea_height = dialog_height - 220;
+      if (textarea_height <= 0) textarea_height = 220;
+    }
+
     var $container = $('#popup_edit_longdescription_input_container');
-    var $edit      = $('<textarea id="popup_edit_longdescription_input" class="texteditor-in-dialog" wrap="soft" style="width: 750px; height: 220px;"></textarea>');
+    var $edit      = $('<textarea id="popup_edit_longdescription_input" class="texteditor-in-dialog texteditor-space-for-toolbar" wrap="soft" style="width: ' + textarea_width + 'px; height: ' + textarea_height + 'px;"></textarea>');
 
     $container.children().remove();
     $container.append($edit);
@@ -44,6 +58,8 @@ namespace('kivi.SalesPurchase', function(ns) {
       id:    'edit_longdescription_dialog',
       dialog: {
         title: kivi.t8('Enter longdescription'),
+        width:  dialog_width,
+        height: dialog_height,
         open:  function() { kivi.focus_ckeditor_when_ready('#popup_edit_longdescription_input'); },
         close: function() { $('#popup_edit_longdescription_input_container').children().remove(); }
       }
@@ -241,9 +257,17 @@ namespace('kivi.SalesPurchase', function(ns) {
     if (!kivi.SalesPurchase.check_required_email_fields())
       return false;
 
+    // ckeditor gets de-initialized when removing the children from
+    // the DOM. Therefore we have to manually preserve its content
+    // over the children's relocation.
+
+    var message = $('#email_form_message').val();
+
     $('#send_email_dialog').children().remove().appendTo('#email_inputs');
     $('#send_email_dialog').dialog('close');
 
+    $('#email_form_message').val(message);
+
     kivi.submit_form_with_action('#form', $('#form').data('send-email-action'));
 
     return true;
@@ -255,6 +279,8 @@ namespace('kivi.SalesPurchase', function(ns) {
 
     $('#print_options').children().remove().appendTo('#email_form_print_options');
 
+    kivi.reinit_widgets();
+
     var to_focus = $('#email_form_to').val() === '' ? 'to' : 'subject';
     $('#email_form_' + to_focus).focus();
   };
@@ -264,10 +290,13 @@ namespace('kivi.SalesPurchase', function(ns) {
     return true;
   };
 
-  this.show_email_dialog = function(send_action) {
+  this.show_email_dialog = function(send_action, vc, vc_id_selector) {
     $('#form').data('send-email-action', send_action || 'send_sales_purchase_email');
 
-    var vc   = $('#vc').val();
+    vc             = vc             || $('#vc').val();
+    vc_id_selector = vc_id_selector || '#' + vc + '_id';
+    var vc_id = $(vc_id_selector).val();
+
     var data = {
       action:       'show_sales_purchase_email_dialog',
       cp_id:        $('#cp_id').val(),
@@ -285,7 +314,7 @@ namespace('kivi.SalesPurchase', function(ns) {
       quonumber:    $('#quonumber').val(),
       type:         $('#type').val(),
       vc:           vc,
-      vc_id:        $('#' + vc + '_id').val(),
+      vc_id:        vc_id,
       project_id:  $('#globalproject_id').val(),
     };
 
@@ -313,7 +342,7 @@ namespace('kivi.SalesPurchase', function(ns) {
   this.activate_send_email_actions_regarding_printout = function() {
     var selected = $('#email_form_attachment_policy').val();
     $('#email_form_attachment_filename').parents('tr')[selected !== 'no_file' ? 'show' : 'hide']();
-    $('#email_form_print_options')[selected === 'normal' ? 'show' : 'hide']();
+    $('#email_form_print_options')[selected !== 'no_file' ? 'show' : 'hide']();
   };
 
   // Printing records.
index 64a1e46..56d524c 100644 (file)
@@ -38,7 +38,7 @@ namespace('kivi.ShopPart', function(ns) {
     });
   }
 
-  ns.add_shop_part = function(part_id,shop_id) {
+  ns.add_shop_part = function() {
     var form = $('form').serializeArray();
     form.push( { name: 'action', value: 'ShopPart/update' }
     );
index b564ffb..4d03451 100644 (file)
@@ -142,6 +142,26 @@ namespace("kivi.Validator", function(ns) {
         ns.annotate($e_annotate);
         return true;
       }
+    },
+    trimmed_whitespaces: function($e, $e_annotate) {
+      $e_annotate = $e_annotate || $e;
+
+      var string = $e.val();
+
+      if ($e.hasClass('tooltipstered'))
+        $e.tooltipster('destroy');
+
+      if (string.match(/^\s|\s$/)) {
+        $e.val(string.trim());
+
+        $e.tooltipster({
+          content: kivi.t8("Leading and trailing whitespaces have been removed."),
+          contentAsHTML: true,
+          theme: 'tooltipster-light',
+        });
+        $e.tooltipster('show');
+      }
+      return true;
     }
   };
 
index 005cdd0..5f9360f 100644 (file)
@@ -337,7 +337,8 @@ namespace("kivi", function(ns) {
       extraPlugins:  'inline_resize',
       toolbar:       buttons,
       disableAutoInline: true,
-      title:         false
+      title:         false,
+      disableNativeSpellChecker: false
     };
 
     config.height = $e.height();
@@ -346,6 +347,14 @@ namespace("kivi", function(ns) {
     var editor = CKEDITOR.inline($e.get(0), config);
     $e.data('ckeditorInstance', editor);
 
+    if ($e.hasClass('texteditor-space-for-toolbar'))
+      editor.on('instanceReady', function() {
+        var editor   = $e.ckeditorGet();
+        var editable = editor.editable();
+        $(editable.$).css("margin-top", "30px");
+      });
+
+
     if ($e.hasClass('texteditor-autofocus'))
       editor.on('instanceReady', function() { ns.focus_ckeditor($e); });
   };
@@ -675,6 +684,49 @@ namespace("kivi", function(ns) {
     $input.prop('selectionStart', position);
     $input.prop('selectionEnd',   position);
   };
+
+  ns._shell_escape = function(str) {
+    if (str.match(/^[a-zA-Z0-9.,_=+/-]+$/))
+      return str;
+
+    return "'" + str.replace(/'/, "'\\''") + "'";
+  };
+
+  ns.call_as_curl = function(params) {
+    params      = params || {};
+    var uri     = document.documentURI.replace(/\?.*/, '');
+    var command = ['curl', '--user', kivi.myconfig.login + ':SECRET', '--request', params.method || 'POST']
+
+    $(params.data || []).each(function(idx, elt) {
+      command = command.concat([ '--form-string', elt.name + '=' + (elt.value || '') ]);
+    });
+
+    command.push(uri);
+
+    return $.map(command, function(elt, idx) {
+      return kivi._shell_escape(elt);
+    }).join(' ');
+  };
+
+  ns.serialize = function(source, target = [], prefix, in_array = false) {
+    let arr_prefix = first => in_array ? (first ? "[+]" : "[]") : "";
+
+    if (Array.isArray(source) ) {
+      source.forEach(( val, i ) => {
+        ns.serialize(val, target, prefix + arr_prefix(i == 0), true);
+      });
+    } else if (typeof source === "object") {
+      let first = true;
+      for (let key in source) {
+        ns.serialize(source[key], target, (prefix !== undefined ? prefix + arr_prefix(first) + "." : "") + key);
+        first = false;
+      }
+    } else {
+      target.push({ name: prefix + arr_prefix(false), value: source });
+    }
+
+    return target;
+  };
 });
 
 kivi = namespace('kivi');
index e36f882..c17b213 100644 (file)
@@ -4,6 +4,7 @@ namespace("kivi").setupLocale({
 "Add function block":"Funktionsblock hinzufügen",
 "Add linked record":"Verknüpften Beleg hinzufügen",
 "Add multiple items":"Mehrere Artikel hinzufügen",
+"Add note":"Notiz erfassen",
 "Add picture":"Bild hinzufügen",
 "Add picture to text block":"Bild dem Textblock hinzufügen",
 "Add section":"Abschnitt hinzufügen",
@@ -61,6 +62,7 @@ namespace("kivi").setupLocale({
 "Edit":"Bearbeiten",
 "Edit article/section assignments":"Zuweisung Artikel/Abschnitte bearbeiten",
 "Edit custom shipto":"Individuelle Lieferadresse bearbeiten",
+"Edit note":"Notiz bearbeiten",
 "Edit picture":"Bild bearbeiten",
 "Edit project link":"Projektverknüpfung bearbeiten",
 "Edit text block":"Textblock bearbeiten",
@@ -89,6 +91,7 @@ namespace("kivi").setupLocale({
 "July":"Juli",
 "Jun":"Jun",
 "June":"Juni",
+"Leading and trailing whitespaces have been removed.":"Leerzeichen wurden vorne und hinten entfernt",
 "Loading...":"Wird geladen...",
 "Map":"Karte",
 "Mar":"März",
@@ -153,6 +156,7 @@ namespace("kivi").setupLocale({
 "Text block picture actions":"Aktionen für Textblockbilder",
 "The URL is missing.":"URL fehlt",
 "The action can only be executed once.":"Die Aktion kann nur einmal ausgeführt werden.",
+"The customer order number is missing. Do you want to continue anyway?":"Die Kundenbestellnummer fehlt. Möchten Sie trotzdem fortfahren?",
 "The description is missing.":"Die Beschreibung fehlt.",
 "The name is missing.":"Der Name fehlt.",
 "The name must only consist of letters, numbers and underscores and start with a letter.":"Der Name darf nur aus Buchstaben (keine Umlaute), Ziffern und Unterstrichen bestehen und muss mit einem Buchstaben beginnen.",
@@ -176,6 +180,7 @@ namespace("kivi").setupLocale({
 "Today":"heute",
 "Toggle marker":"Markierung umschalten",
 "Transaction description":"Vorgangsbezeichnung",
+"Transfer stock":"Lagerbewegungen",
 "Tue":"Di",
 "Tuesday":"Dienstag",
 "Update":"Erneuern",
index b03ddb3..4306694 100644 (file)
@@ -4,6 +4,7 @@ namespace("kivi").setupLocale({
 "Add function block":"",
 "Add linked record":"",
 "Add multiple items":"",
+"Add note":"",
 "Add picture":"",
 "Add picture to text block":"",
 "Add section":"",
@@ -61,6 +62,7 @@ namespace("kivi").setupLocale({
 "Edit":"",
 "Edit article/section assignments":"",
 "Edit custom shipto":"",
+"Edit note":"",
 "Edit picture":"",
 "Edit project link":"",
 "Edit text block":"",
@@ -89,6 +91,7 @@ namespace("kivi").setupLocale({
 "July":"",
 "Jun":"",
 "June":"",
+"Leading and trailing whitespaces have been removed.":"",
 "Loading...":"",
 "Map":"",
 "Mar":"",
@@ -153,6 +156,7 @@ namespace("kivi").setupLocale({
 "Text block picture actions":"",
 "The URL is missing.":"",
 "The action can only be executed once.":"",
+"The customer order number is missing. Do you want to continue anyway?":"",
 "The description is missing.":"",
 "The name is missing.":"",
 "The name must only consist of letters, numbers and underscores and start with a letter.":"",
@@ -176,6 +180,7 @@ namespace("kivi").setupLocale({
 "Today":"",
 "Toggle marker":"",
 "Transaction description":"",
+"Transfer stock":"",
 "Tue":"",
 "Tuesday":"",
 "Update":"",
index 820a29e..e148066 100755 (executable)
@@ -13,6 +13,8 @@ $self->{texts} = {
   ' Date missing!'              => ' Datum fehlt!',
   ' bytes, max='                => ' Bytes, Maximum=',
   ' missing!'                   => ' fehlt!',
+  '"#1" seems to be a faulty list of email addresses. After extracing addresses (#2) too many characters are left.' => '"#1" scheint fehlerhaft zu sein. Es wurden E-Mail Adressen extrahiert (#2), aber es sind noch zu viele Zeichen übrig.',
+  '"#1" seems to be a faulty list of email addresses. No addresses could be extracted.' => '"#1" scheint fehlerhaft zu sein. Es konnte keine E-Mail Adresse extrahiert werden',
   '#1 (custom variable)'        => '#1 (benutzerdefinierte Variable)',
   '#1 MD'                       => '#1 PT',
   '#1 additional part(s)'       => '#1 zusätzliche(r) Artikel',
@@ -174,9 +176,11 @@ $self->{texts} = {
   'Add Delivery Order'          => 'Lieferschein erfassen',
   'Add Document from \'#1\''    => 'Dokument von \'#1\' hinzufügen',
   'Add Dunning'                 => 'Mahnung erzeugen',
+  'Add Final Invoice'           => 'Schlussrechnung erfassen',
   'Add Follow-Up'               => 'Wiedervorlage erstellen',
   'Add Follow-Up for #1'        => 'Wiedervorlage für #1 erstellen',
   'Add General Ledger Transaction' => 'Dialogbuchen',
+  'Add Invoice for Advance Payment' => 'Anzahlungsrechnung erfassen',
   'Add Letter'                  => 'Brief hinzufügen',
   'Add Part'                    => 'Ware erfassen',
   'Add Price Factor'            => 'Preisfaktor erfassen',
@@ -186,6 +190,7 @@ $self->{texts} = {
   'Add Purchase Order'          => 'Lieferantenauftrag erfassen',
   'Add Quotation'               => 'Angebot erfassen',
   'Add RFQ'                     => 'Preisanfrage erfassen',
+  'Add RMA Delivery Order'      => 'Retouren-Lieferschein erfassen',
   'Add Request for Quotation'   => 'Anfrage erfassen',
   'Add Requirement Spec'        => 'Pflichtenheft erfassen',
   'Add Requirement Spec Template' => 'Pflichtenheftvorlage erfassen',
@@ -194,6 +199,7 @@ $self->{texts} = {
   'Add Sales Order'             => 'Auftrag erfassen',
   'Add Service'                 => 'Dienstleistung erfassen',
   'Add Storno Credit Note'      => 'Gutschrift Storno hinzufügen',
+  'Add Supplier Delivery Order' => 'Beistell-Lieferschein erfassen',
   'Add Transaction'             => 'Dialogbuchen',
   'Add User'                    => 'Neuer Benutzer',
   'Add User Group'              => 'Neue Benutzergruppe',
@@ -252,11 +258,15 @@ $self->{texts} = {
   'Added sections and function blocks: #1' => 'Hinzugefügte Abschnitte und Funktionsblöcke: #1',
   'Added text blocks: #1'       => 'Hinzugefügte Textblöcke: #1',
   'Addition'                    => 'Zusatz',
+  'Additional Billing Address'  => 'Zusätzliche Rechnungsadresse',
+  'Additional Billing Addresses' => 'Zusätzliche Rechnungsadressen',
   'Additional articles'         => 'Zusätzliche Artikel',
   'Additional articles actions' => 'Aktionen zu zusätzlichen Artikeln',
   'Additionally the invoice is marked for direct debit and would have been checked automatically had the bank information been entered.' => 'Weiterhin ist die Rechnung für Lastschrifteinzug vorgesehen und wäre standardmäßig ausgewählt, wenn die Bankinformationen eingetragen wären.',
   'Additionally the invoice is not marked for direct debit and would have been checked automatically had the bank information been entered.' => 'Weiterhin ist die Rechnung nicht für Lastschrifteinzug vorgesehen und wäre standardmäßig ausgewählt, wenn die Bankinformationen eingetragen wären.',
   'Address'                     => 'Adresse',
+  'Address deleted.'            => 'Adresse gelöscht',
+  'Address is in use and was flagged invalid.' => 'Adresse wurde benutzt und wird nur als ungültig markiert',
   'Administration'              => 'Administration',
   'Administration area'         => 'Administration',
   'Advance turnover tax return' => 'Umsatzsteuervoranmeldung',
@@ -277,6 +287,7 @@ $self->{texts} = {
   'All pay postings successfully imported.' => 'Alle Lohnbuchungen erfolgreich importiert.',
   'All payments have already been posted.' => 'Es wurden bereits alle Zahlungen verbucht.',
   'All payments must be posted before the payment list can be downloaded.' => 'Alle Zahlungen müssen verbucht werden, bevor die Zahlungsliste heruntergeladen werden kann.',
+  'All phone numbers'           => 'Alle Telefonnummern',
   'All price sources'           => 'Alle Preisquellen',
   'All reports'                 => 'Alle Berichte (Kontenübersicht, Summen- u. Saldenliste, Erfolgsrechnung, GuV, BWA, Bilanz, Projektbuchungen)',
   'All the other clients will start with an empty set of WebDAV folders.' => 'Alle anderen Mandanten werden mit einem leeren Satz von Dokumenten-Ordnern ausgestattet.',
@@ -305,6 +316,7 @@ $self->{texts} = {
   'Amount BT'                   => 'Betrag Bank',
   'Amount Due'                  => 'Betrag fällig',
   'Amount and net amount are calculated by kivitendo. "verify_amount" and "verify_netamount" can be used for sanity checks.' => 'Betrag und Nettobetrag werden von kivitendo berechnet. "verify_amount" und "verify_netamount" können für Plausibilitätsprüfungen angegeben werden.',
+  'Amount has wrong format.'    => 'Betrag hat falsches Format.',
   'Amount less skonto'          => 'Betrag abzgl. Skonto',
   'Amount payable'              => 'Noch zu bezahlender Betrag',
   'Amount payable less discount' => 'Noch zu bezahlender Betrag abzüglich Skonto',
@@ -351,6 +363,7 @@ $self->{texts} = {
   'Assemblies'                  => 'Erzeugnisse',
   'Assembly'                    => 'Erzeugnis',
   'Assembly (typeabbreviation)' => 'E',
+  'Assembly Item Qty'           => 'Menge für Erzeugnis',
   'Assembly Last Cost'          => 'Erzeugnis-Einkaufspreis',
   'Assembly Number missing!'    => 'Erzeugnisnummer fehlt!',
   'Assembly creation transfers services' => 'Erzeugnis fertigen berücksichtigt Dienstleistungen',
@@ -422,6 +435,7 @@ $self->{texts} = {
   'Balances'                    => 'Salden',
   'Balancing'                   => 'Bilanzierung',
   'Bank'                        => 'Bank',
+  'Bank Account Id Number (Swiss)' => 'Bankkonto Identifikationsnummer (Schweiz)',
   'Bank Code'                   => 'BLZ',
   'Bank Code (long)'            => 'Bankleitzahl (BLZ)',
   'Bank Code Number'            => 'Bankleitzahl',
@@ -431,6 +445,7 @@ $self->{texts} = {
   'Bank Transaction'            => 'Bankkonto',
   'Bank Transaction is in a closed period.' => 'Die Bankbewegung befindet sich innerhalb eines geschlossenen Zeitraums.',
   'Bank account'                => 'Bankkonto',
+  'Bank account id number invalid. Must be 6 digits.' => 'Bank Identifikationsnummer ungültig. (6-stellig)',
   'Bank accounts'               => 'Bankkonten',
   'Bank code'                   => 'Bankleitzahl',
   'Bank code of the goal/source' => 'Bankleitzahl von Ziel- oder Quellkonto',
@@ -531,6 +546,7 @@ $self->{texts} = {
   'CSV Export successful!'      => 'CSV-Export erfolgreich!',
   'CSV export'                  => 'CSV-Export',
   'CSV export -- options'       => 'CSV-Export -- Optionen',
+  'CSV import: additional billing addresses' => 'CSV-Import: zusätzliche Rechnungsadressen',
   'CSV import: ar transactions' => 'CSV Import: Debitorenbuchungen',
   'CSV import: bank transactions' => 'CSV Import: Bankbewegungen',
   'CSV import: contacts'        => 'CSV-Import: Ansprechpersonen',
@@ -553,6 +569,7 @@ $self->{texts} = {
   'Cancel Accounts Payables Transaction' => 'Kreditorenbuchung stornieren',
   'Cancel Accounts Receivables Transaction' => 'Debitorenbuchung stornieren',
   'Cancelling is disallowed. Either undo or balance the current payments until the open amount matches the invoice amount' => 'Storno verboten, da Zahlungen zum Beleg vorhanden sind. Entweder die Zahlungen löschen oder mit umgekehrten Vorzeichen ausbuchen, sodass der offene Betrag dem Rechnungsbetrag entspricht.',
+  'Cannot Post AP transaction with tax included!' => 'Kann diesen kreditorischen Beleg nicht mit "Steuer im Preis inbegriffen" verbuchen!',
   'Cannot add Booking, reason: #1 DB: #2 ' => 'Kann die Buchung nicht hinzufügen, Grund: #1 DB: #2',
   'Cannot allocate parts.'      => 'Es sind nicht genügend Artikel vorhanden',
   'Cannot change transaction in a closed period!' => 'In einem bereits abgeschlossenen Zeitraum kann keine Buchung verändert werden!',
@@ -568,12 +585,15 @@ $self->{texts} = {
   'Cannot delete transaction!'  => 'Buchung kann nicht gelöscht werden!',
   'Cannot delete vendor!'       => 'Lieferant kann nicht gelöscht werden!',
   'Cannot find matching template for this print request. Please contact your template maintainer. I tried these: #1.' => 'Konnte keine passende Vorlage für diesen Druckauftrag finden. Bitte benachrichtigen Sie Ihren Vorlagenadministrator. Die folgenden Pfade wurden durchsucht: #1 ',
+  'Cannot get shippingOrderAddressId for #1' => 'Finde das Feld shippingOrderAddressId für #1 nicht.',
   'Cannot have a value in both Debit and Credit!' => 'Es kann nicht gleichzeitig Soll und Haben gebucht werden!',
   'Cannot post Payment!'        => 'Zahlung kann nicht gebucht werden!',
   'Cannot post Receipt!'        => 'Beleg kann nicht gebucht werden!',
   'Cannot post a transaction without a value!' => 'Eine Buchung ohne Betrag kann nicht vorgenommen werden!',
   'Cannot post invoice and/or transfer out! Error message:' => 'Rechnung kann nicht gebucht oder es kann nicht ausgelagert werden. Fehlermeldung:',
   'Cannot post invoice for a closed period!' => 'Das Rechnungsdatum fällt in einen abgeschlossen Zeitraum!',
+  'Cannot post invoice for advance payment with more than one tax' => 'Anzahlungsrechnung mit mehr als einem Steuersatz kann nicht gebucht werden',
+  'Cannot post invoice for advance payment with taxincluded' => 'Eine Anzahlungsrechnung mit Steuer im Preis inbegriffen kann nicht gebucht werden',
   '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!',
@@ -638,7 +658,6 @@ $self->{texts} = {
   'Check Details'               => 'Bitte Angaben überprüfen',
   'Check connectivity'          => 'Verbindungstest',
   'Check for duplicates'        => 'Dublettencheck',
-  'Check full signature'        => 'Volle Signatur prüfen',
   'Check on ap transaction'     => 'Prüfen bei Kreditorenbuchung',
   'Check on ar transaction'     => 'Prüfen bei Debitorenbuchung',
   'Check on gl transaction'     => 'Prüfen bei Dialogbuchung',
@@ -657,6 +676,7 @@ $self->{texts} = {
   'Cleared Balance'             => 'abgeschlossen',
   'Cleared/uncleared only'      => 'Status abgeglichen',
   'Clearing Tax Received (No 71)' => 'Verrechnung des Erstattungsbetrages erwünscht (Zeile 71)',
+  'Clearing account for advance payments' => 'Verrechnungskonto für Anzahlungen',
   'Client'                      => 'Mandant',
   'Client #1'                   => 'Mandant #1',
   'Client Configuration'        => 'Mandantenkonfiguration',
@@ -687,6 +707,7 @@ $self->{texts} = {
   'Company name'                => 'Firmenname',
   'Company name and address'    => 'Firmenname und -adresse',
   'Company settings'            => 'Firmeneinstellungen',
+  'Company\'s email signature'  => 'Firmen-E-Mail-Signatur',
   'Compare to'                  => 'Gegenüberstellen zu',
   'Complexities'                => 'Komplexitätsgrade',
   'Complexity'                  => 'Komplexität',
@@ -729,7 +750,7 @@ $self->{texts} = {
   'Costs'                       => 'Kosten',
   'Could not create new project #1' => 'Neues Projekt #1 kann nicht angelegt werden',
   'Could not extract Factur-X/ZUGFeRD data, data and error message:' => 'Konnte keine Factur-X-/ZUGFeRD-Daten extrahieren, folgende Fehlermeldung und das PDF:',
-  'Could not find an entry for this part in the pricegroup.' => 'Konnte keine Eintrag für diesen Artikel in der Preisgruppe finden.',
+  'Could not find an entry for this part in the pricegroup.' => 'Konnte keinen Eintrag für diesen Artikel in der Preisgruppe finden.',
   'Could not load class #1 (#2): "#3"' => 'Konnte Klasse #1 (#2) nicht laden: "#3"',
   'Could not load class #1, #2' => 'Konnte Klasse #1 nicht laden: "#2"',
   'Could not load employee'     => 'Konnte Benutzer nicht laden',
@@ -804,7 +825,10 @@ $self->{texts} = {
   'Create one from the context menu by right-clicking on this text.' => 'Erstellen Sie einen aus dem Kontextmenü, indem Sie auf diesen Text rechtsklicken.',
   'Create order'                => 'Auftrag erstellen',
   'Create sales invoices with Factur-X/ZUGFeRD data' => 'Verkaufsrechnungen mit Factur-X-/ZUGFeRD-Daten erzeugen',
+  'Create sales invoices with Swiss QR-bill' => 'Verkaufsrechnungen mit Schweizer QR-Rechnung erzeugen',
   'Create tables'               => 'Tabellen anlegen',
+  'Create variant IBAN without reference' => 'Variante IBAN ohne Referenz erzeugen',
+  'Create variant QR-IBAN with QR reference' => 'Variante QR-IBAN mit QR-Referenz erzeugen',
   'Create with profile \'Factur-X 1.0.05/ZUGFeRD 2.1.1 extended\'' => 'Mit Profil »Factur-X 1.0.05/ZUGFeRD 2.1.1 extended«',
   'Create with profile \'Factur-X 1.0.05/ZUGFeRD 2.1.1 extended\' (test mode)' => 'Mit Profil »Factur-X 1.0.05/ZUGFeRD 2.1.1 extended« (Test-Modus)',
   'Create with profile \'XRechnung 2.0.0\'' => 'Mit Profil »XRechnung 2.0.0«',
@@ -814,6 +838,7 @@ $self->{texts} = {
   'Created for'                 => 'Erstellt für',
   'Created on'                  => 'Erstellt am',
   'Creating Documents'          => 'Erzeuge Dokumente',
+  'Creating Factur-X/ZUGFeRD invoices is not enabled for this customer.' => 'Das Erzeugen von Factur-X/ZUGFeRD-Rechnungen ist für diesen Kunden nicht aktiviert.',
   'Creating invoices'           => 'Erzeuge Rechnungen',
   'Creating the PDF failed:'    => 'PDF-Erzeugung fehlgeschlagen:',
   'Creation Date'               => 'Erstelldatum',
@@ -855,6 +880,7 @@ $self->{texts} = {
   'Current version'             => 'Aktuelle Version',
   'Current year'                => 'Aktuelles Jahr',
   'Currently #1 delivery orders can be converted into invoices and printed.' => 'Momentan können #1 Lieferscheine in Rechnungen umgewandelt werden.',
+  'Custom Billing Address'      => 'Abweichende Rechnungsadresse',
   'Custom CSV format'           => 'Eigenes CSV-Format',
   'Custom Variables'            => 'Benutzerdefinierte Variablen',
   'Custom data export'          => 'Benutzerdefinierter Datenexport',
@@ -871,11 +897,13 @@ $self->{texts} = {
   'Customer Order Number'       => 'Bestellnummer des Kunden',
   'Customer Part Number'        => 'Kunden-Art-Nr.',
   'Customer Price'              => 'Kundenpreis',
+  'Customer Proposals'          => 'Kundenvorschläge',
   'Customer deleted!'           => 'Kunde gelöscht!',
   'Customer details'            => 'Kundendetails',
   'Customer missing!'           => 'Kundenname fehlt!',
   'Customer must not be empty.' => 'Kunden darf nicht leer sein.',
   'Customer not found'          => 'Kunde nicht gefunden',
+  'Customer number invalid. Must be less then or equal to 6 digits after prefix.' => 'Kundennummer ungültig. (kleiner/gleich 6 Stellen nach Prefix)',
   'Customer of assigned order must match customer.' => 'Kunde des zugeordneten Auftrags muss mit dem gewählten Kunden übereinstimmen.',
   'Customer of assigned project must match customer.' => 'Kunde des zugeordneten Projekts muss mit dem gewählten Kunden übereinstimmen.',
   'Customer saved'              => 'Kunde gespeichert',
@@ -949,6 +977,7 @@ $self->{texts} = {
   'Date Paid'                   => 'Zahlungsdatum',
   'Date and timestamp variables: If the default value equals \'NOW\' then the current date/current timestamp will be used. Otherwise the default value is copied as-is.' => 'Datums- und Uhrzeitvariablen: Wenn der Standardwert \'NOW\' ist, so wird das aktuelle Datum/die aktuelle Uhrzeit eingefügt. Andernfalls wird der Standardwert so wie er ist benutzt.',
   'Date missing!'               => 'Datum fehlt!',
+  'Date of Last Payment'        => 'Letzter Zahlungseingang',
   'Date the payment is due in full' => 'Das Datum, bis die Rechnung in voller Höhe bezahlt werden muss',
   'Date the payment is due with discount' => 'Das Datum, bis die Rechnung unter Abzug von Skonto bezahlt werden kann',
   'Datev export encoding'       => 'DATEV-Export Kodierung',
@@ -974,6 +1003,7 @@ $self->{texts} = {
   'Decrease'                    => 'Verringern',
   'Default (no language selected)' => 'Standard (keine Sprache ausgewählt)',
   'Default Accounts'            => 'Standardkonten',
+  'Default Billing Address'     => 'Standard-Rechnungsadresse',
   'Default Bin'                 => 'Standard-Lagerplatz',
   'Default Bin with ignoring onhand' => 'Standard-Lagerplatz für Auslagern ohne Prüfung auf Bestand',
   'Default Client (unconfigured)' => 'Standardmandant (unkonfiguriert)',
@@ -985,6 +1015,7 @@ $self->{texts} = {
   'Default Transfer with services' => 'Ein- /Auslagern von Dienstleistungen über Standard-Lagerplatz',
   'Default Warehouse'           => 'Standard-Lager',
   'Default Warehouse with ignoring onhand' => 'Standard-Lager für Auslagern ohne Prüfung auf Bestand',
+  'Default address flag'        => 'Standard-Adresse-Schalter',
   'Default article for converting into quotations and orders' => 'Standardartikel für Konvertierung von Pflichtenheften in Angebote und Aufträge',
   'Default booking group'       => 'Standardbuchungsgruppe',
   'Default client'              => 'Standardmandant',
@@ -1011,7 +1042,9 @@ $self->{texts} = {
   'Delete Documents'            => 'Dokumente löschen',
   'Delete Images'               => 'Bilder löschen',
   'Delete Shipto'               => 'Lieferadresse löschen',
+  'Delete address'              => 'Adresse löschen',
   'Delete all'                  => 'Alle Löschen',
+  'Delete for Customers'        => 'Bei Kunden löschen',
   'Delete links'                => 'Verknüpfungen löschen',
   'Delete picture'              => 'Bild löschen',
   'Delete printfiles'           => 'Dokumente löschen',
@@ -1031,8 +1064,11 @@ $self->{texts} = {
   'Delivery Order Date'         => 'Lieferscheindatum',
   'Delivery Order Date missing!' => 'Lieferscheindatum fehlt!',
   'Delivery Order Number'       => 'Lieferscheinnummer',
+  'Delivery Order Type'         => 'Lieferschein Typ',
   'Delivery Order created'      => 'Lieferschein erstellt',
   'Delivery Order deleted!'     => 'Lieferschein gelöscht!',
+  'Delivery Order has been deleted' => 'Lieferschein wurde gelöscht',
+  'Delivery Order has been saved' => 'Lieferschein wurde gespeichert',
   'Delivery Order(s) for full qty created' => 'Lieferschein(e) mit kompletter Menge erstellt',
   'Delivery Orders'             => 'Lieferscheine',
   'Delivery Plan'               => 'Lieferplan',
@@ -1094,6 +1130,7 @@ $self->{texts} = {
   'Do not change the tax rate of taxkey 0.' => 'Ändern Sie nicht den Steuersatz vom Steuerschlüssel 0.',
   'Do not check for duplicates' => 'Nicht nach Dubletten suchen',
   'Do not create Factur-X/ZUGFeRD invoices' => 'Keine Factur-X-/ZUGFeRD-Rechnungen erzeugen',
+  'Do not create QR-bill invoices' => 'Keine QR-Rechnungen erzeugen',
   'Do not leave booking form?'  => 'Buchungsmaske nicht verlassen?',
   'Do not link to a project.'   => 'Nicht mit einem Projekt verknüpfen.',
   'Do not modify this position' => 'Diese Position nicht verändern',
@@ -1120,6 +1157,7 @@ $self->{texts} = {
   'Do you really want to mark the selected entries as booked?' => 'Möchten Sie die ausgewählten Einträge wirklich als gebucht markieren?',
   'Do you really want to print?' => 'Wollen Sie wirklich drucken?',
   'Do you really want to revert to this version?' => 'Möchten Sie wirklich auf diese Version zurücksetzen?',
+  'Do you really want to transfer the stock and set this order to delivered?' => 'Wollen Sie wirklich alle Lagerbewegungen durchführen?',
   'Do you really want to undo the selected SEPA exports? You have to reassign the export again.' => 'Möchten Sie wirklich die ausgewählten SEPA-Exports rückgängig machen? Der Export muss anschließend neu erzeugt werden.',
   'Do you really want to unimport the selected documents?' => 'Möchten Sie wirklich diese Dateien an die Quelle zurückgeben?',
   'Do you want to <b>limit</b> your search?' => 'Möchten Sie Ihre Suche <b>spezialisieren</b>?',
@@ -1220,9 +1258,11 @@ $self->{texts} = {
   'Edit Dunning Process Config' => 'Mahnwesenkonfiguration bearbeiten',
   'Edit Employee #1'            => 'Benutzer #1 bearbeiten',
   'Edit Factur-X/ZUGFeRD notes' => 'Factur-X-/ZUGFeRD-Notizen bearbeiten',
+  'Edit Final Invoice'          => 'Schlussrechnung bearbeiten',
   'Edit Follow-Up'              => 'Wiedervorlage bearbeiten',
   'Edit Follow-Up for #1'       => 'Wiedervorlage für #1 bearbeiten',
   'Edit General Ledger Transaction' => 'Buchung im Hauptbuch bearbeiten',
+  'Edit Invoice for Advance Payment' => 'Anzahlungsrechnung bearbeiten',
   'Edit Letter'                 => 'Brief bearbeiten',
   'Edit Part'                   => 'Ware bearbeiten',
   'Edit Preferences for #1'     => 'Einstellungen von #1 bearbeiten',
@@ -1231,6 +1271,7 @@ $self->{texts} = {
   'Edit Purchase Delivery Order' => 'Lieferschein (Einkauf) bearbeiten',
   'Edit Purchase Order'         => 'Lieferantenauftrag bearbeiten',
   'Edit Quotation'              => 'Angebot bearbeiten',
+  'Edit RMA Delivery Order'     => 'Retouren-Lieferschein bearbeiten',
   'Edit Request for Quotation'  => 'Anfrage bearbeiten',
   'Edit SEPA strings'           => 'Begriffe bei SEPA-Überweisungen bearbeiten',
   'Edit Sales Delivery Order'   => 'Lieferschein (Verkauf) bearbeiten',
@@ -1239,6 +1280,8 @@ $self->{texts} = {
   'Edit Service'                => 'Dienstleistung bearbeiten',
   'Edit Storno Credit Note'     => 'Storno Gutschrift bearbeiten',
   'Edit Storno Invoice'         => 'Stornorechnung bearbeiten',
+  'Edit Storno Invoice for Advance Payment' => 'Storno-Anzahlungsrechnung bearbeiten',
+  'Edit Supplier Delivery Order' => 'Beistell-Lieferschein bearbeiten',
   'Edit User'                   => 'Benutzerdaten bearbeiten',
   'Edit User Group'             => 'Benutzergruppe bearbeiten',
   'Edit Vendor'                 => 'Lieferant editieren',
@@ -1305,14 +1348,15 @@ $self->{texts} = {
   'Edit time recordings of all staff members' => 'Zeiterfassungseinträge aller Mitarbeiter bearbeiten',
   'Edit title'                  => 'Titiel bearbeiten',
   'Edit units'                  => 'Einheiten bearbeiten',
-  'Edit user signature'         => 'Benutzersignatur bearbeiten',
   'Editable'                    => 'Bearbeitbar',
   'Either there are no open invoices, or you have already initiated bank transfers with the open amounts for those that are still open.' => 'Entweder gibt es keine offenen Rechnungen, oder es wurden bereits Überweisungen über die offenen Beträge aller offenen Rechnungen erstellt.',
   'Element disabled'            => 'Element deaktiviert',
   'Email'                       => 'E-Mail',
+  'Email address'               => 'E-Mail-Adresse',
   'Email journal'               => 'E-Mail-Journal',
   'Email of the delivery order recipient' => 'E-Mail des Lieferscheinempfängers',
   'Email of the invoice recipient' => 'E-Mail des Rechnungsempfängers',
+  'Email signature'             => 'E-Mail-Signatur',
   'Employee'                    => 'Bearbeiter',
   'Employee #1 saved!'          => 'Benutzer #1 gespeichert!',
   'Employee (database ID)'      => 'Bearbeiter (Datenbank-ID)',
@@ -1336,17 +1380,21 @@ $self->{texts} = {
   'Equity'                      => 'Passiva',
   'Erfolgsrechnung'             => 'Erfolgsrechnung',
   'Error'                       => 'Fehler',
+  'Error getting QR-Bill type.' => 'Fehler in QR-Rechnung Varianten Auswahl.',
   'Error handling'              => 'Fehlerbehandlung',
   'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
   'Error in position #1: You must either assign no stock at all or the full quantity of #2 #3.' => 'Fehler in Position #1: Sie müssen einer Position entweder gar keinen Lagereingang oder die vollständige im Lieferschein vermerkte Menge von #2 #3 zuweisen.',
   'Error in position #1: You must either assign no transfer at all or the full quantity of #2 #3.' => 'Fehler in Position #1: Sie müssen einer Position entweder gar keinen Lagerausgang oder die vollständige im Lieferschein vermerkte Menge von #2 #3 zuweisen.',
   'Error in row #1: The quantity you entered is bigger than the stocked quantity.' => 'Fehler in Zeile #1: Die angegebene Menge ist größer als die vorhandene Menge.',
+  'Error mapping biller countrycode.' => 'Fehler beim Erzeugen des Ländercodes für Rechnungssteller.',
+  'Error mapping customer countrycode.' => 'Fehler beim Erzeugen des Ländercodes für Kunden.',
   'Error message from the database driver:' => 'Fehlermeldung des Datenbanktreibers:',
   'Error message from the database: #1' => 'Fehlermeldung der Datenbank: #1',
   'Error message from the webshop api:' => 'Fehlermeldung der Webshop Api',
   'Error when saving: #1'       => 'Fehler beim Speichern: #1',
   'Error while applying year-end bookings!' => 'Fehler beim Durchführen der Abschlußbuchungen!',
   'Error while creating project with project number of new order number, project number #1 already exists!' => 'Fehler beim Erstellen eines Projekts mit der Projektnummer der neuen Auftragsnummer, Projektnummer #1 existiert bereits!',
+  'Error while saving shop order #1. DB Error #2. Generic exception #3.' => 'Fehler beim Speichern der Shop-Bestellung #1. DB Fehler #2. Genereller Fehler #3.',
   'Error with default taxzone'  => 'Ungültige Standardsteuerzone',
   'Error!'                      => 'Fehler!',
   'Error: #1'                   => 'Fehler: #1',
@@ -1459,6 +1507,7 @@ $self->{texts} = {
   'Existing contacts (with column \'cp_id\')' => 'Existierende Ansprechpersonen (mit Spalte \'cp_id\')',
   'Existing customers/vendors with same customer/vendor number' => 'Existierende Kunden/Lieferanten mit derselben Kunden-/Lieferantennummer',
   'Existing file on server'     => 'Auf dem Server existierende Datei',
+  'Existing finished follow-ups for this item' => 'Erledigte Wiedervorlagen für dieses Dokument',
   'Existing pending follow-ups for this item' => 'Noch nicht erledigte Wiedervorlagen für dieses Dokument',
   'Existing profiles'           => 'Existierende Profile',
   'Existing templates'          => 'Vorhandene Belegvorlagen',
@@ -1486,6 +1535,7 @@ $self->{texts} = {
   'Extended status'             => 'Erweiterter Status',
   'Extension Of Time'           => 'Dauerfristverlängerung',
   'Factor'                      => 'Faktor',
+  'Factur-X/ZUGFeRD'            => 'Factur-X/ZUGFeRD',
   'Factur-X/ZUGFeRD import'     => 'Factur-X-/ZUGFeRD-Import',
   'Factur-X/ZUGFeRD invoice'    => 'Factur-X-/ZUGFeRD-Rechnung',
   'Factur-X/ZUGFeRD notes for each invoice' => 'Factur-X-/ZUGFeRD-Notizen für jede Rechnung',
@@ -1495,6 +1545,7 @@ $self->{texts} = {
   'Feb'                         => 'Feb',
   'February'                    => 'Februar',
   'Fee'                         => 'Gebühr',
+  'Fetch from last order number is not implemented' => 'Das Abholen ab der letzten Auftragsnummer ist nicht implementiert',
   'Fetch order'                 => 'Hole Bestellung',
   'Field'                       => 'Feld',
   'File'                        => 'Datei',
@@ -1519,6 +1570,9 @@ $self->{texts} = {
   'Filter for item variables'   => 'Filter für benutzerdefinierte Artikelvariablen',
   'Filter parts'                => 'Artikel filtern',
   'Filter record template'      => 'Filter für Buchungsvorlagen',
+  'Final Invoice'               => 'Schlussrechnung',
+  'Final Invoice (one letter abbreviation)' => 'F',
+  'Final Invoice, please use mark as paid manually' => 'Rechnungstyp Schlussrechnung, bitte den Beleg manuell als bezahlt markieren',
   'Financial Controlling'       => 'Finanzcontrolling',
   'Financial Controlling Report' => 'Finanzcontrollingbericht',
   'Financial Overview'          => 'Finanzübersicht',
@@ -1555,6 +1609,7 @@ $self->{texts} = {
   'For part "#1" there is no default warehouse and bin for ignoring onhand defined.' => 'Für Artikel "#1" ist kein Standardlager/-lagerplatz für das Auslagern ohne Bestandsprüfung angegeben.',
   'For purchase delivery orders, warn on workflow to invoice if not stocked in' => 'Warnung in Einkaufslieferscheinen beim Workflow zur Rechnung ausgeben, wenn nicht eingelagert',
   'For sales delivery orders, warn on workflow to invoice if not stocked out' => 'Warnung in Verkaufslieferscheinen beim Workflow zur Rechnung ausgeben, wenn nicht ausgelagert',
+  'For sales invoices, warn if invoice has no delivery order as a predecessor' => 'Bei Verkaufsrechnungen warnen, dass die Rechnung nicht aus einem Lieferschein generiert wurde.',
   'For type "customer" the perl module JSON is required. Please check this on system level: $ ./scripts/installation_check.pl' => 'Für den Typ "Kunde" wird das Perl Module JSON benötigt. Überprüfbar im Installationspfad mit: $ ./scripts/installation_check.pl',
   'Foreign Exchange Gain'       => 'Wechselkurserträge',
   'Foreign Exchange Loss'       => 'Wechselkursaufwendungen',
@@ -1580,11 +1635,13 @@ $self->{texts} = {
   'Front page'                  => 'Hauptseite',
   'Full Access'                 => 'Vollzugriff',
   'Full Preview'                => 'Alles',
+  'Full Text'                   => 'Volltext',
   'Full access to all functions' => 'Vollzugriff auf alle Funktionen',
   'Function block'              => 'Funktionsblock',
   'Function block actions'      => 'Funktionsblockaktionen',
   'Function block number format' => 'Format der Funktionsblocknummerierung',
   'Function/position'           => 'Funktion/Position',
+  'Further Invoice for Advance Payment' => 'Weitere Anzahlungsrechnung',
   'GL Transaction'              => 'Dialogbuchung',
   'GL Transaction (abbreviation)' => 'DB',
   'GL Transactions'             => 'Dialogbuchungen',
@@ -1604,6 +1661,7 @@ $self->{texts} = {
   'General ledger transactions can only be changed on the day they are posted.' => 'Dialogbuchungen können nur am Buchungstag geändert werden.',
   'General settings'            => 'Allgemeine Einstellungen',
   'Generate and print sales delivery orders' => 'Erzeuge und drucke Lieferscheine',
+  'Generating the document failed: #1' => 'Das Dokument konnte nicht erzeugt werden: #1',
   'Germany'                     => 'Deutschland',
   'Get one order'               => 'Hole eine Bestellung',
   'Get one order by shopordernumber' => 'Hole eine Bestellung über Shopbestellnummer',
@@ -1627,6 +1685,7 @@ $self->{texts} = {
   'Groups valid for this client' => 'Für Mandanten gültige Gruppen',
   'HTML'                        => 'HTML',
   'HTML Templates'              => 'HTML-Vorlagen',
+  'HTML field'                  => 'HTML-Feld',
   'Handling of WebDAV'          => 'Behandlung von WebDAV',
   'Hardcopy'                    => 'Seite drucken',
   'Has item type'               => 'Hat Regeltypen',
@@ -1683,14 +1742,21 @@ $self->{texts} = {
   'If disabled purchase invoices can only be created by conversion from existing requests for quotations, purchase orders and purchase delivery orders.' => 'Falls deaktiviert, so können Einkaufsrechnungen nur durch Umwandlung aus bestehenden Preisanfragen, Lieferantenaufträgen und Einkaufslieferscheinen angelegt werden.',
   'If disabled sales orders cannot be converted into sales invoices directly.' => 'Falls deaktiviert, so können Verkaufsaufträge nicht direkt in Verkaufsrechnungen umgewandelt werden.',
   'If disabled sales quotations cannot be converted into sales invoices directly.' => 'Falls deaktiviert, so können Verkaufsangebote nicht direkt in Verkaufsrechnungen umgewandelt werden.',
+  'If disabled, record numbers for sales records & purchase records produced by our side will always be auto-generated and cannot be changed later.' => 'Falls deaktiviert, werden Belegnummern in Verkaufs- und Einkaufsbelegen, die auf unserer Seite erzeugt wurden, immer automatisch vergeben und können anschließend nicht mehr geändert werden.',
   'If enabled Factur-X/ZUGFeRD conformant sales invoice PDFs will be created.' => 'Falls aktiviert, werden Factur-X-/ZUGFeRD-konforme PDFs für Verkaufsrechnungen erzeugt.',
   'If enabled a column will be shown in sales and purchase orders that lists both the amount and the value not shipped yet for each item.' => 'Falls eingeschaltet, wird für jede Position in Auftragsbestätigungen und Lieferantenaufträgen eine Spalte mit noch nicht gelieferter Menge und Wert angezeigt.',
+  'If enabled a warning will be shown if a sales invoices is created without having a sales delivery order as a predecessor.' => 'Falls aktiv, wird eine Warnung beim Buchen einer Verkaufsrechnung angezeigt, falls es keinen Lieferschein als Vorgänger gibt.',
   'If enabled a warning will be shown in purchase delivery orders on workflow to invoices if positions are not stocked in.' => 'Falls aktiviert, wird eine Warnung beim Workflow von Einkaufslieferscheinen zu Rechnungen ausgegeben, wenn die Positionen noch nicht eingelagert sind.',
   'If enabled a warning will be shown in sales and purchase orders if there are two or more positions of the same part (new controller only).' => 'Falls eingeschaltet, wird eine Warnung angezeigt, wenn der Auftrag mehrere gleiche Artikel enthält (nur neuer Controller).',
   'If enabled a warning will be shown in sales and purchase orders if there the delivery date is empty.' => 'Falls aktiviert, Warnungen ausgeben sobald Aufträge (Einkauf- und Verkauf) keinen Liefertermin haben.',
+  'If enabled a warning will be shown in sales delivery orders if the customer order number is missing.' => 'Falls aktiviert, wird eine Warnung beim Speichern von Verkaufsaufträgen ausgegeben, wenn die Kundenbestellnummer fehlt.',
   'If enabled a warning will be shown in sales delivery orders on workflow to invoices if positions are not stocked out.' => 'Falls aktiviert, wird eine Warnung beim Workflow von Verkaufslieferscheinen zu Rechnungen ausgegeben, wenn die Positionen noch nicht ausgelagert sind.',
   'If enabled only those projects that are assigned to the currently selected customer are offered for selection in sales records.' => 'Wenn eingeschaltet, so werden in Verkaufsbelegen nur diejenigen Projekte zur Auswahl angeboten, die dem aktuell ausgewählten Kunden zugewiesen wurden.',
   'If enabled purchase and sales records cannot be saved if no transaction description has been entered.' => 'Wenn angeschaltet, so können Einkaufs- und Verkaufsbelege nicht gespeichert werden, solange keine Vorgangsbezeichnung eingegeben wurde.',
+  'If enabled sales invoices created using OpenDocument/OASIS format will include data for Swiss QR-Bill creation.' => 'Falls aktiviert, enthalten Rechnungen im OpenDocument/OASIS Format, Daten zur Schweizer QR-Rechnung.',
+  'If enabled the record links view starts always from the sales order including all sublevels' => 'Falls aktiv, werden die verknüpften Belege immer vom Verkaufsauftrag inkl. aller darunterliegenden Belege angezeigt',
+  'If enabled try to overrule the brower\'s back button to prevent double booking of sales invoices.' => 'Falls aktiviert, wird versucht, den Zurück-Knopf des Browsers auszuhebel, um doppeltes Buchen von Verkaufsrechnungen zu verhindern.',
+  'If enabled, when saving parts the partsgroup must be not be empty.' => 'Falls aktiviert muß beim Speichern von Artikeln eine Warengruppe ausgewählt sein.',
   'If item not found, allow creation of new item' => 'Falls Artikel nicht gefunden, erlaube Erfassen eines Neuen',
   'If left empty the default sender from the kivitendo configuration will be used (key \'email_from\' in section \'periodic_invoices\'; current value: #1).' => 'Falls leer, so wird der Standardabsender aus der kivitendo-Konfiguration genutzt (Schlüssel »email_from« in Abschnitt »periodic_invoices«; aktueller Wert: #1).',
   'If missing then the start date will be used.' => 'Falls es fehlt, so wird die erste Rechnung für das Startdatum erzeugt.',
@@ -1788,6 +1854,7 @@ $self->{texts} = {
   'Internal Phone List'         => 'Interne Telefonliste',
   'Internal comment'            => 'Interne Bemerkungen',
   'Internet'                    => 'Internet',
+  'Interpolate variables in texts of positions' => 'Variablen in Positionstexten interpolieren',
   'Into bin'                    => 'Eingelagert',
   'Intra-Community supply'      => 'Gelangensbestätigung',
   'Introduction of clients'     => 'Einführung von Mandanten',
@@ -1801,6 +1868,7 @@ $self->{texts} = {
   'Invalid follow-up ID.'       => 'Ungültige Wiedervorlage-ID.',
   'Invalid quantity.'           => 'Die Mengenangabe ist ungültig.',
   'Invalid request type \'#1\'' => 'Ungültiger Request-Typ \'#1\'',
+  'Invalid todo for updating Part' => 'Ungültiger Wert für das Feld todo bei Artikel aktualisieren',
   'Invalid transactions'        => 'Ungültige Buchungen',
   'Invalid variable #1'         => 'Ungültige Variable #1',
   'Invdate'                     => 'Rechnungsdatum',
@@ -1816,6 +1884,7 @@ $self->{texts} = {
   'Invnumber missing!'          => 'Rechnungsnummer fehlt!',
   'Invoice'                     => 'Rechnung',
   'Invoice (one letter abbreviation)' => 'R',
+  'Invoice Copy'                => 'Rechnungskopie',
   'Invoice Date'                => 'Rechnungsdatum',
   'Invoice Date missing!'       => 'Rechnungsdatum fehlt!',
   'Invoice Duedate'             => 'Fälligkeitsdatum',
@@ -1828,9 +1897,13 @@ $self->{texts} = {
   'Invoice email and Contact Person' => 'E-Mail des Rechnungsempfängers und CC an Ansprechpartner',
   'Invoice email settings'      => 'E-Mail Rechnungsversand',
   'Invoice filter'              => 'Rechnungsfilter',
+  'Invoice for Advance Payment' => 'Anzahlungsrechnung',
+  'Invoice for Advance Payment (one letter abbreviation)' => 'A',
+  'Invoice for Advance Payment with Storno (abbreviation)' => 'A(S)',
   'Invoice for fees'            => 'Rechnung über Gebühren',
   'Invoice has already been storno\'d!' => 'Diese Rechnung wurde bereits storniert.',
   'Invoice number'              => 'Rechnungsnummer',
+  'Invoice number invalid. Must be less then or equal to 7 digits after prefix.' => 'Rechnungsnummer ungültig. (kleiner/gleich 7 Stellen nach Prefix)',
   'Invoice to:'                 => 'Rechnung an:',
   'Invoice total'               => 'Die Rechnungssumme',
   'Invoice total less discount' => 'Rechnungssumme abzüglich Skonto',
@@ -1840,7 +1913,6 @@ $self->{texts} = {
   'Invoices with payments cannot be canceled.' => 'Rechnungen mit Zahlungen können nicht storniert werden.',
   'Invoices, Credit Notes & AR Transactions' => 'Rechnungen, Gutschriften & Debitorenbuchungen',
   'Is Searchable'               => 'Durchsuchbar',
-  'Is sales'                    => 'Verkauf',
   'Is this a summary account to record' => 'Sammelkonto für',
   'It can be changed later but must be unique within the installation.' => 'Er ist nachträglich änderbar, muss aber im System eindeutig sein.',
   'It is not allowed that a summary account occurs in a drop-down menu!' => 'Ein Sammelkonto darf nicht in Aufklappmenüs aufgenommen werden!',
@@ -1911,6 +1983,7 @@ $self->{texts} = {
   'Lastcost'                    => 'Einkaufspreis',
   'Lastcost (with X being a number)' => 'Einkaufspreis (X ist eine fortlaufende Zahl)',
   'Lastname'                    => 'Nachname',
+  'Leading and trailing whitespaces have been removed.' => 'Leerzeichen wurden vorne und hinten entfernt',
   'Left'                        => 'Links',
   'Letter'                      => 'Brief',
   'Letter Draft'                => 'Briefentwurf',
@@ -1975,6 +2048,7 @@ $self->{texts} = {
   'Long Description (quotations & orders)' => 'Langtext (Angebote & Aufträge)',
   'Long Description for invoices' => 'Langtext für Rechnungen',
   'Long Description for quotations & orders' => 'Langtext für Angebote & Aufträge',
+  'Longdescription dialog size percentage from main window (0 means fix values)' => 'Prozentuale Größe des Langtext-Dialogs im Verhältnis zum Hauptfenster (0 bedeutet feste Größe)',
   'Loss'                        => 'Verlust',
   'Loss carried forward account' => 'Verlustvortragskonto',
   'Luxembourg'                  => 'Luxemburg',
@@ -1986,7 +2060,7 @@ $self->{texts} = {
   'MT940 import preview'        => 'MT940-Import-Vorschau',
   'MT940 import result'         => 'MT940-Import-Ergebnis',
   'Mails'                       => 'E-Mails',
-  'Main Contact Person'         => 'Hauptansprechpartner',
+  'Main Contact Person'         => 'Hauptansprechperson',
   'Main Preferences'            => 'Grundeinstellungen',
   'Main sorting'                => 'Hauptsortierung',
   'Make'                        => 'Lieferant',
@@ -2078,6 +2152,9 @@ $self->{texts} = {
   'Name does not make sense without any bsooqr options' => 'Option "Name in gewählten Belegen" wird ignoriert.',
   'Name in Selected Records'    => 'Name in gewählten Belegen',
   'Name of the goal/source (if field names remote_name and remote_name_1 exist they will be combined into field "remote_name")' => 'Name des Ziel- oder Quellkontos (wenn die Spalten remote_name und remote_name_1 existieren werden diese zu Feld "remote_name" zusammengefügt)',
+  'Need a image title'          => 'Benötige einen Titel für das Bild',
+  'Need a valid Shop Part for updating Part' => 'Benötige eine gültiges Shop Part Objekt, um den Artikel zu aktualisieren.',
+  'Need a workflow for Supplier Delivery Order' => 'Benötige zwingend einen Workflow-Vorgänger für den Beistell-Lieferschein',
   'Need at least one original position for the workflow Order to Delivery Order!' => 'Benötige mindestens eine Position die aus dem Auftrag übernommen wurde, ansonsten ist der Workflow inkosistent.',
   'Need charge number!'         => 'Benötige Chargennummer!',
   'Negative reductions are possible to model price increases.' => 'Negative Abschläge sind möglich um Aufschläge zu modellieren.',
@@ -2097,6 +2174,7 @@ $self->{texts} = {
   'New Password'                => 'Neues Passwort',
   'New Purchase Price Rule'     => 'Neue Einkaufspreisregel',
   'New Sales Price Rule'        => 'Neue Verkaufspreisregel',
+  'New address'                 => 'Neue Adresse',
   'New client #1: The database configuration fields "host", "port", "name" and "user" must not be empty.' => 'Neuer Mandant #1: Die Datenbankkonfigurationsfelder "Host", "Port" und "Name" dürfen nicht leer sein.',
   'New client #1: The name must be unique and not empty.' => 'Neuer Mandant #1: Der Name darf nicht leer und muss eindeutig sein.',
   'New contact'                 => 'Neue Ansprechperson',
@@ -2117,16 +2195,20 @@ $self->{texts} = {
   'No 1:n or n:1 relation'      => 'Keine 1:n oder n:1 Beziehung',
   'No AP Record Template for this vendor found, please add one' => 'Konnte keine Kreditorenbuchungsvorlage für diesen Lieferanten finden, bitte legen Sie eine an.',
   'No AP template was found.'   => 'Keine Kreditorenbuchungsvorlage gefunden.',
+  'No Billing and ship to address, for Order Number #1 with ID Billing #2 and ID Shipping #3' => 'Keine Rechnungs- und Lieferadresse zur Bestellnummer #1 mit Rechnungs-ID #2 und Liefer-ID #3 gefunden',
   'No Company Address given'    => 'Keine Firmenadresse hinterlegt!',
   'No Company Name given'       => 'Kein Firmenname hinterlegt!',
   'No Customer was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Endkunde gefunden',
   'No GL template was found.'   => 'Keine Dialogbuchungsvorlage gefunden.',
   'No Journal'                  => 'Kein Journal',
+  'No Order Number'             => 'Keine Auftragsnummer',
+  'No Order items fetched'      => 'Keine Auftragspositionen gefunden',
   'No Shopdescription'          => 'Keine Shop-Artikelbeschreibung',
   'No Shopimages'               => 'Keine Shop-Bilder',
   'No VAT Info for this Factur-X/ZUGFeRD invoice, please ask your vendor to add this for his Factur-X/ZUGFeRD data.' => 'Konnte keine UST-ID für diese Factur-X-/ZUGFeRD-Rechnungen finden, bitte fragen Sie bei Ihren Lieferanten nach, ob dieses Feld im Factur-X-/ZUGFeRD-Datensatz gesetzt wird.',
   'No Vendor was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Händler gefunden',
   'No action defined.'          => 'Keine Aktion definiert.',
+  'No address selected to delete' => 'Keine Adresse zum Löschen ausgewählt',
   'No article has been selected yet.' => 'Es wurde noch kein Artikel ausgewählt.',
   'No articles have been added yet.' => 'Es wurden noch keine Artikel hinzugefügt.',
   'No assembly has been selected yet.' => 'Es wurde noch kein Erzeugnis ausgewahlt.',
@@ -2134,8 +2216,10 @@ $self->{texts} = {
   'No bank account chosen!'     => 'Kein Bankkonto ausgewählt!',
   'No bank account configured for bank code/BIC #1, account number/IBAN #2.' => 'Kein Bankkonto für BLZ/BIC #1, Kontonummer/IBAN #2 konfiguriert.',
   'No bank account flagged for Factur-X/ZUGFeRD usage was found.' => 'Es wurde kein Bankkonto gefunden, das für Nutzung mit Factur-X/ZUGFeRD markiert ist.',
+  'No bank account flagged for QRBill usage was found.' => 'Kein Bankkonto markiert für QR-Rechnung gefunden.',
   'No bank information has been entered in this customer\'s master data entry. You cannot create bank collections unless you enter bank information.' => 'Für diesen Kunden wurden in seinen Stammdaten keine Kontodaten hinterlegt. Solange dies nicht geschehen ist, können Sie keine Überweisungen für den Lieferanten anlegen.',
   'No bank information has been entered in this vendor\'s master data entry. You cannot create bank transfers unless you enter bank information.' => 'Für diesen Lieferanten wurden in seinen Stammdaten keine Kontodaten hinterlegt. Solange dies nicht geschehen ist, können Sie keine Überweisungen für den Lieferanten anlegen.',
+  'No billing city'             => 'Die Stadt für die Rechnungsadresse fehlt',
   'No bins have been added to this warehouse yet.' => 'Es wurden zu diesem Lager noch keine Lagerplätze angelegt.',
   'No carry-over chart configured!' => 'Kein Saldenvortragskonto konfiguriert!',
   'No changes since previous version.' => 'Keine Änderungen seit der letzten Version.',
@@ -2143,6 +2227,7 @@ $self->{texts} = {
   'No contact selected to delete' => 'Keine Ansprechperson zum Löschen ausgewählt',
   'No contra account selected!' => 'Kein Gegenkonto ausgewählt!',
   'No custom data exports have been created yet.' => 'Es wurden noch keine benutzerdefinierten Datenexporte angelegt.',
+  'No customer email'           => 'Die E-Mail-Adresse des Kunden fehlt',
   'No customer has been selected yet.' => 'Es wurde noch kein Kunde ausgewählt.',
   'No customer selected or found!' => 'Kein Kunde selektiert oder keinen gefunden!',
   'No data was found.'          => 'Es wurden keine Daten gefunden.',
@@ -2185,8 +2270,10 @@ $self->{texts} = {
   'No sections created yet'     => 'Keine Abschnitte erstellt',
   'No sections have been created so far.' => 'Bisher wurden noch keine Abschnitte angelegt.',
   'No sections have been created yet.' => 'Es wurden noch keine Abschnitte angelegt.',
+  'No shipto city'              => 'Die Stadt für die Lieferadresse fehlt',
   'No shipto selected to delete' => 'Keine Lieferadresse zum Löschen ausgewählt',
   'No start date given, setting to #1' => 'Kein Startdatum gegeben, setze Startdatum auf #1',
+  'No stock to transfer'        => 'Keine Lagerbewegungen vorhanden',
   'No such job #1 in the database.' => 'Hintergrund-Job #1 existiert nicht mehr.',
   'No summary account'          => 'Kein Sammelkonto',
   'No superuser credentials were entered.' => 'Es wurden keine Super-Benutzer-Anmeldedaten eingegeben.',
@@ -2220,6 +2307,7 @@ $self->{texts} = {
   'Not done yet'                => 'Noch nicht fertig',
   'Not enough in stock for the serial number #1' => 'Nicht genug auf Lager von der Seriennummer #1',
   'Not obsolete'                => 'Gültig',
+  'Not yet implemented'         => 'Noch nicht implementiert',
   'Note'                        => 'Hinweis',
   'Note that parameter names must not be quoted.' => 'Beachten Sie, dass Parameternamen nicht in Anführungszeichen stehen dürfen.',
   'Note: Taxkeys must have a "valid from" date, and will not behave correctly without.' => 'Hinweis: Steuerschlüssel sind fehlerhaft ohne "Gültig ab" Datum',
@@ -2285,6 +2373,7 @@ $self->{texts} = {
   'Oops. No valid action found to dispatch. Please report this case to the kivitendo team.' => 'Ups. Es wurde keine gültige Funktion zum Aufrufen gefunden. Bitte berichten Sie diesen Fall den kivitendo-Entwicklern.',
   'Open'                        => 'Offen',
   'Open Amount'                 => 'Offener Betrag',
+  'Open Amount at Last Payment Date' => 'Offener Betrag zum letzten Zahlungseingang',
   'Open Items'                  => 'Offene Posten',
   'Open Orders'                 => 'Offene Aufträge',
   'Open a further kivitendo window or tab' => 'Weiteres kivitendo-Fenster/-Tab öffnen',
@@ -2309,6 +2398,7 @@ $self->{texts} = {
   'Order amount'                => 'Auftragswert',
   'Order deleted!'              => 'Auftrag gelöscht!',
   'Order item search'           => 'Auftragsartikelsuche',
+  'Order number invalid. Must be less then or equal to 7 digits after prefix.' => 'Auftragsnummer ungültig. (kleiner/gleich 7 Stellen nach Prefix)',
   'Order probability'           => 'Auftragswahrscheinlichkeit',
   'Order probability & expected billing date' => 'Auftragswahrscheinlichkeit & vorrauss. Abrechnungsdatum',
   'Order value periodicity'     => 'Auftragswert basiert auf Periodizität',
@@ -2320,6 +2410,7 @@ $self->{texts} = {
   'Orders'                      => 'Aufträge',
   'Orders / Delivery Orders deleteable' => 'Aufträge / Lieferscheine löschbar',
   'Orders to fetch'             => 'Anzahl Bestellungen holen',
+  'Orders to fetch neeeds a positive Integer' => 'Die Anzahl der zu holenden Aufträge muss eine positive Ganzzahl sein',
   'Orientation'                 => 'Seitenformat',
   'Orig. Size w/h'              => 'Orig. Größe b/h',
   'Origin of personal data'     => 'Herkunft der personenbezogenen Daten',
@@ -2371,11 +2462,12 @@ $self->{texts} = {
   'Part (typeabbreviation)'     => 'W',
   'Part Classification'         => 'Artikel-Klassifizierung',
   'Part Description'            => 'Artikelbeschreibung',
+  'Part Description is too long for this Shopware version. It should have lower than 255 characters.' => 'Artikelbeschreibung enthält mehr als 255 Zeichen. Shopware in dieser Version kann nur Artikelbeschreibungen mit weniger als 255 Zeichen verarbeiten.',
   'Part Description missing!'   => 'Artikelbezeichnung fehlt!',
   'Part Notes'                  => 'Bemerkungen',
   'Part Number'                 => 'Artikelnummer',
   'Part Number missing!'        => 'Artikelnummer fehlt!',
-  'Part Test'                   => '',
+  'Part Test'                   => 'Artikel-Test',
   'Part Type'                   => 'Artikel-Typ',
   'Part Unit'                   => 'Einheit',
   'Part classifications'        => 'Artikel-Klassifizierungen',
@@ -2397,6 +2489,7 @@ $self->{texts} = {
   'Partsgroup'                  => 'Warengruppe',
   'Partsgroup (database ID)'    => 'Warengruppe (Datenbank-ID)',
   'Partsgroup (name)'           => 'Warengruppe (Name)',
+  'Partsgroup is required for parts' => 'Warengruppe ist Pflichtfeld für Artikel',
   'Partsgroups'                 => 'Warengruppen',
   'Partsgroups where variables are shown' => 'Warengruppen, bei denen Variablen angezeigt werden',
   'Password'                    => 'Passwort',
@@ -2438,8 +2531,14 @@ $self->{texts} = {
   'Perpetual inventory'         => 'Bestandsmethode',
   'Personal settings'           => 'Persönliche Einstellungen',
   'Phone'                       => 'Telefon',
+  'Phone Notes'                 => 'Telefonnotizen',
   'Phone extension'             => 'Durchwahl',
   'Phone extension missing in user configuration' => 'Durchwahl fehlt in der Benutzerkonfiguration',
+  'Phone note has been created.' => 'Die Telefonnotiz wurde angelegt.',
+  'Phone note has been deleted.' => 'Die Telefonnotiz wurde gelöscht.',
+  'Phone note has been updated.' => 'Die Telefonnotiz wurde aktualisiert.',
+  'Phone note needs a subject and a body.' => 'Eine Telefonnotiz muss einen Betreff und einen Text haben.',
+  'Phone note not found for this order.' => 'Diese Telefonnotiz wurde für dieses Dokument nicht gefunden.',
   'Phone password'              => 'Telefonpasswort',
   'Phone password missing in user configuration' => 'Telefonpasswort fehlt in der Benutzerkonfiguration',
   'Phone1'                      => 'Telefon 1 ',
@@ -2540,6 +2639,7 @@ $self->{texts} = {
   'Preset email text for sales invoices with direct debit' => 'Vorbelegter E-Mail-Text für Rechnungen mit Bankeinzug',
   'Preset email text for sales orders' => 'Vorbelegter E-Mail-Text für Aufträge',
   'Preset email text for sales quotations' => 'Vorbelegter E-Mail-Text für Angebote',
+  'Prevent browser\'s back button in sales invoices' => 'Browser-Zurück-Knopf bei Verkaufsrechnungen verhindern',
   'Preview'                     => 'Vorschau',
   'Preview Mode'                => 'Vorschaumodus',
   'Previous month'              => 'vorheriger Monat',
@@ -2621,7 +2721,6 @@ $self->{texts} = {
   'Project (description)'       => 'Projekt (Beschreibung)',
   'Project (number)'            => 'Projektnummer',
   'Project Description'         => 'Projektbeschreibung',
-  'Project Details'             => 'Projektdetails',
   'Project Link'                => 'Projektverknüpfung',
   'Project Number'              => 'Projektnummer',
   'Project Numbers'             => 'Projektnummern',
@@ -2641,6 +2740,7 @@ $self->{texts} = {
   'Proposal'                    => 'Vorschlag',
   'Proposals'                   => 'Vorschläge',
   'Protocol'                    => 'Protokoll',
+  'Proxy'                       => 'Proxy',
   'Prozentual/Absolut'          => 'Prozentual/Absolut',
   'Purchase'                    => 'Einkauf',
   'Purchase (typeabbreviation)' => 'E',
@@ -2665,6 +2765,9 @@ $self->{texts} = {
   'Purpose'                     => 'Verwendungszweck',
   'Purpose (if field names purpose, purpose1, purpose2 ... exist they will all combined into the field "purpose")' => 'Verwendungszweck (wenn die Spalten purpose, purpose1, purpose2 ... existieren werden diese zum Feld "purpose" zusammengefügt)',
   'Purpose/Reference'           => 'Verwendungszweck und Referenz',
+  'QR bill without amount'      => 'QR-Rechnung ohne Betrag',
+  'QR-Code placeholder image: QRCodePlaceholder not found in template.' => 'QR-Code Platzhalter Bild: QRCodePlaceholder nicht gefunden.',
+  'QR-Image generation failed: ' => 'QR-Code Erzeugung fehlgeschlagen: ',
   'QUEUED'                      => 'In Warteschlange',
   'Qty'                         => 'Menge',
   'Qty according to delivery order' => 'Menge laut Lieferschein',
@@ -2706,6 +2809,9 @@ $self->{texts} = {
   'RFQ Date'                    => 'Anfragedatum',
   'RFQ Number'                  => 'Anfragenummer',
   'RFQs'                        => 'Preisanfragen',
+  'RMA Delivery Order'          => 'Retouren-Lieferschein',
+  'RMA Delivery Orders'         => 'Retouren-Lieferscheine',
+  'RMA delivery order'          => 'Retouren-Lieferschein',
   'ROP'                         => 'Mindestlagerbestand',
   'Ranges of numbers'           => 'Nummernkreise',
   'Re-numbering all sections and function blocks in the order they are currently shown cannot be undone.' => 'Das Neu-Nummerieren aller Abschnitte und Funktionsblöcke kann nicht rückgängig gemacht werden.',
@@ -2731,6 +2837,7 @@ $self->{texts} = {
   'Record Vendor Invoice'       => 'Einkaufsrechnung erfassen',
   'Record in'                   => 'Buchen auf',
   'Record number'               => 'Belegnummer',
+  'Record numbers changeable'   => 'Änderbarkeit von Belegnummern',
   'Record templates'            => 'Belegvorlagen',
   'Record type to create'       => 'Anzulegender Belegtyp',
   'Record\'s files'             => 'Belegdateien',
@@ -2783,7 +2890,7 @@ $self->{texts} = {
   'Report separately'           => 'Preis separat ausweisen',
   'Reports'                     => 'Berichte',
   'Representative'              => 'Vertreter',
-  'Representative for Customer' => 'Vertreter für Kunden',
+  'Representative for Customer' => 'Vertreter für Kunden (aktuell (3.6) deaktiviert)',
   'Reqdate'                     => 'Liefertermin',
   'Reqdate is #1'               => 'Liefertermin ist #1',
   'Reqdate is after #1'         => 'Liefertermin nach #1',
@@ -2924,12 +3031,16 @@ $self->{texts} = {
   'Save and Close'              => 'Speichern und schließen',
   'Save and Delivery Order'     => 'Speichern und Lieferschein',
   'Save and E-mail'             => 'Speichern und E-Mail',
+  'Save and Final Invoice'      => 'Speichern und Schlussrechnung',
+  'Save and Further Invoice for Advance Payment' => 'Speichern und weitere Anzahlungsrechnung',
   'Save and Invoice'            => 'Speichern und Rechnung erfassen',
+  'Save and Invoice for Advance Payment' => 'Speichern und Anzahlungsrechnung',
   'Save and Order'              => 'Speichern und Auftrag erfassen',
   'Save and Purchase Order'     => 'Speichern und Lieferantenauftrag',
   'Save and Quotation'          => 'Speichern und Angebot',
   'Save and RFQ'                => 'Speichern und Lieferantenanfrage',
   'Save and Sales Order'        => 'Speichern und Kundenauftrag',
+  'Save and Supplier Delivery Order' => 'Speichern und Beistelllieferschein',
   'Save and close'              => 'Speichern und schließen',
   'Save and execute'            => 'Speichern und ausführen',
   'Save and keep open'          => 'Speichern und geöffnet lassen',
@@ -2995,7 +3106,7 @@ $self->{texts} = {
   'Send email'                  => 'E-Mail verschicken',
   'Send invoice via email'      => 'Rechnung via E-Mail verschicken',
   'Send printout of record'     => 'Belegausdruck mitschicken',
-  'Send the last printout created for this record' => 'Den zuletzt erstellen Belegausdruck mitschicken',
+  'Send the last or create the first version for this record' => 'Den zuletzt erstellten oder neuen Belegausdruck verschicken',
   'Sender'                      => 'AbsenderIn',
   'Sent emails can be optionally stored in the database with or without their attachments.' => 'Gesendete E-Mails können optional mit oder ohne ihre Anhänge in der Datenbank gespeichert werden.',
   'Sent on'                     => 'Verschickt am',
@@ -3036,6 +3147,8 @@ $self->{texts} = {
   'Shipping Address'            => 'Lieferadresse',
   'Shipping Point'              => 'Versandort',
   'Shipping address (name)'     => 'Name der Lieferadresse',
+  'Shipping cost article is not implemented' => 'Versandkosten-Artikel ist nicht implementiert',
+  'Shipping cost article not implemented' => 'Lieferkosten-Artikel nicht implementiert',
   'Shipping costs'              => 'Versandkosten',
   'Shipping date'               => 'Lieferdatum',
   'Shippingcosts'               => 'Versandkosten',
@@ -3164,6 +3277,7 @@ $self->{texts} = {
   'Skipping due to same partnumber in csv file' => 'Eintrag in Datei mit doppelter Artikelnummer wird übersprungen',
   'Skipping non-existent article' => 'Überspringe nicht vorhandenen Artikel',
   'Skonto'                      => 'Skonto',
+  'Skonto Tax Correction for'   => 'Skonto-Steuerkorrektur für',
   'Skonto Terms'                => 'Zahlungsziel Skonto',
   'Skonto amount'               => 'Skontobetrag',
   'Skonto information'          => 'Skonto Information',
@@ -3217,6 +3331,7 @@ $self->{texts} = {
   'Stock Qty for Date'          => 'Lagerbestand am',
   'Stock for part #1'           => 'Bestand für Artikel #1',
   'Stock levels'                => 'Lagerbestände',
+  'Stock transfered'            => 'Lagerbewegungen ausgeführt',
   'Stock value'                 => 'Bestandswert',
   'StockInfo'                   => 'Lagerinfo',
   'Stocked Qty'                 => 'Lagermenge',
@@ -3232,6 +3347,8 @@ $self->{texts} = {
   'Storage Type for shopimages' => 'Speichertyp für Shopbilder',
   'Storing PDF in storage backend failed: #1' => 'Speichern der PDF-Datei im Datei-Speicher fehlgeschlagen: #1',
   'Storing PDF to webdav folder failed: #1' => 'Speichern der PDF im WebDAV Ordner fehlgeschlagen: #1',
+  'Storing the document in the storage backend failed: #1' => 'Das Ablegen des Dokuments im Dokumentenspeicher schlug fehl: #1',
+  'Storing the document to the WebDAV folder failed: #1' => 'Das Ablegen des Dokuments im WebDAV-Ordner schlug fehl: #1',
   'Storing the emails in the journal is currently disabled in the client configuration.' => 'Das Speichern von versendeten E-Mails ist derzeit in der Mandantenkonfigurierung abgeschaltet.',
   'Storno'                      => 'Storno',
   'Storno (one letter abbreviation)' => 'S',
@@ -3264,6 +3381,11 @@ $self->{texts} = {
   'Sun'                         => 'So',
   'Sunday'                      => 'Sonntag',
   'Superuser name'              => 'Datenbankadministrator',
+  'Supplier Delivery Order'     => 'Beistell-Lieferschein',
+  'Supplier Delivery Order has been deleted' => 'Beistell-Lieferschein wurde gelöscht',
+  'Supplier Delivery Order has been saved' => 'Beistell-Lieferschein wurde gespeichert',
+  'Supplier Delivery Orders'    => 'Beistell-Lieferscheine',
+  'Supplier delivery order'     => 'Beistell-Lieferschein',
   'Supplies'                    => 'Lieferungen',
   'Surname'                     => 'Nachname',
   'Switzerland'                 => 'Schweiz',
@@ -3339,10 +3461,10 @@ $self->{texts} = {
   'Text blocks back'            => 'Textblöcke hinten',
   'Text blocks front'           => 'Textblöcke vorne',
   'Text field'                  => 'Textfeld',
-  'Text field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the text field. They default to 30 and 5 respectively.' => 'Textfelder: \'WIDTH=w HEIGHT=h\' setzen die Breite und die Höhe des Textfeldes. Wenn nicht anders angegeben, so werden sie 30 Zeichen breit und fünf Zeichen hoch dargestellt.',
+  'Text field and HTML field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the field in pixels. They default to 225 and 90 respectively.' => 'Textfelder und HTML-Felder: \'WIDTH=w HEIGHT=h\' setzen die Breite und die Höhe des Feldes in Pixeln. Wenn nicht anders angegeben, so werden sie 225 Pixel breit und 90 Pixel hoch dargestellt.',
   'Text in CSV File'            => 'Spalte in der CSV Datei',
   'Text variables: \'MAXLENGTH=n\' sets the maximum entry length to \'n\'.' => 'Textzeilen: \'MAXLENGTH=n\' setzt eine Maximallänge von n Zeichen.',
-  'Text, text field and number variables: The default value will be used as-is.' => 'Textzeilen, Textfelder und Zahlenvariablen: Der Standardwert wird so wie er ist übernommen.',
+  'Text, text field, HTML field and number variables: The default value will be used as-is.' => 'Textzeilen, Textfelder, HTML-Felder und Zahlenvariablen: Der Standardwert wird so wie er ist übernommen.',
   'Texts for invoices'          => 'Texte für Rechnungen',
   'Texts for quotations & orders' => 'Texte für Angebote & Aufträge',
   'That export does not exist.' => 'Dieser Export existiert nicht.',
@@ -3359,6 +3481,8 @@ $self->{texts} = {
   'The Factur-X/ZUGFeRD version used is not supported.' => 'Die verwendete Factur-X-/ZUGFeRD-Version wird nicht unterstützt.',
   'The GL transaction #1 has been deleted.' => 'Die Dialogbuchung #1 wurde gelöscht.',
   'The Geierlein path has not been set in the configuration.' => 'Der Geierlein-Pfad wurde in der Konfigurationsdatei nicht gesetzt.',
+  'The Host Name is missing'    => 'Der Name des Servers fehlt',
+  'The Host Name seems invalid' => 'Der Name des Servers sieht ungültig aus, bspw.: www.server.com',
   'The IBAN \'#1\' is not valid as IBANs in #2 must be exactly #3 characters long.' => 'Die IBAN \'#1\' ist ungültig, da IBANs in #2 genau #3 Zeichen lang sein müssen.',
   'The IBAN is missing.'        => 'Die IBAN fehlt.',
   'The ID #1 is not a valid database ID.' => 'Die ID #1 ist keine gültige Datenbank-ID.',
@@ -3367,6 +3491,8 @@ $self->{texts} = {
   'The PDF has been created'    => 'Die PDF-Datei wurde erstellt.',
   'The PDF has been previewed'  => 'PDF-Druckvorschau ausgeführt',
   'The PDF has been printed'    => 'Das PDF-Dokument wurde gedruckt.',
+  'The Protocol for Host Name seems invalid (expected: http:// or https://)!' => 'Das Protokoll für den Server sieht falsch aus. Erwartet wird "http://" oder "https://".',
+  'The Proxy Name seems invalid' => 'Der Hostname des Proxys sieht falsch aus',
   'The SEPA export has been created.' => 'Der SEPA-Export wurde erstellt',
   'The SEPA strings have been saved.' => 'Die bei SEPA-Überweisungen verwendeten Begriffe wurden gespeichert.',
   'The SQL query can be parameterized with variables named as follows: <%name%>.' => 'Die SQL-Abfrage kann mittels Variablen wie folgt parametrisiert werden: <%Variablenname%>.',
@@ -3452,6 +3578,7 @@ $self->{texts} = {
   'The custom variable has been saved.' => 'Die benutzerdefinierte Variable wurde gespeichert.',
   'The custom variable is in use and cannot be deleted.' => 'Die benutzerdefinierte Variable ist in Benutzung und kann nicht gelöscht werden.',
   'The customer name is missing.' => 'Der Kundenname fehlt.',
+  'The customer order number is missing. Do you want to continue anyway?' => 'Die Kundenbestellnummer fehlt. Möchten Sie trotzdem fortfahren?',
   'The customer\'s bank account number (IBAN) is missing.' => 'Die Kontonummer (IBAN) des Kunden fehlt.',
   'The database for user management and authentication does not exist. You can create let kivitendo create it with the following parameters:' => 'Die Datenbank für die Benutzeranmeldung existiert nicht. Sie können Sie von kivitendo automatisch mit den folgenden Parametern anlegen lassen:',
   'The database host is missing.' => 'Der Datenbankhost fehlt.',
@@ -3480,6 +3607,8 @@ $self->{texts} = {
   'The display of (mainly) picker results can be configured. To insert the value of one option use <%Name%>.' => 'Die Anzeigenamen von (hauptsächlich) Auswahl-Ergebnissen (Picker) können konfiguriert werden. Um einen Wert einer Option in die Anzeige aufzunehmen, verwenden Sie <%Name%>.',
   'The document has been changed by another user. No mail was sent. Please reopen it in another window and copy the changes to the new window' => 'Die Daten wurden bereits von einem anderen Benutzer verändert. Deshalb ist das Dokument ungültig und es wurde keine E-Mail verschickt. Bitte öffnen Sie das Dokument erneut in einem extra Fenster und übertragen Sie die Daten',
   'The document has been changed by another user. Please reopen it in another window and copy the changes to the new window' => 'Die Daten wurden bereits von einem anderen Benutzer verändert. Deshalb ist das Dokument ungültig. Bitte öffnen Sie das Dokument erneut in einem extra Fenster und übertragen Sie die Daten',
+  'The document has been created.' => 'Das Dokument wurde erzeugt.',
+  'The document has been printed.' => 'Das Dokument wurde gedruckt.',
   'The documents have been sent to the printer \'#1\'.' => 'Die Dokumente sind zum Drucker \'#1\' geschickt',
   'The dunnings have been printed.' => 'Die Mahnung(en) wurden gedruckt.',
   'The email has been sent.'    => 'Die E-Mail wurde verschickt.',
@@ -3516,6 +3645,7 @@ $self->{texts} = {
   'The greetings have been saved.' => 'Die Anreden wurden gespeichert',
   'The installation is currently locked.' => 'Die Installation ist momentan gesperrt.',
   'The installation is currently unlocked.' => 'Die Installation ist momentan entsperrt.',
+  'The invoice is not linked with a sales delivery order. Post anyway?' => 'Diese Rechnung ist mit keinem Lieferschein verknüpft. Dennoch Buchen?',
   'The invoice recipient can either be a selected contact person (default) or the email adress set in the master data of the customer. Additionally a contact persons mail and the company\'s invoicing mail can be combined.' => 'Der E-Mail-Rechnungsempfänger ist entweder mit dem Ansprechpartner des Belegs vorbelegt (Standard) oder mit der E-Mail-Rechnungsadresse aus den Stammdaten. Alternativ können beide (Ansprechpartner in CC) vorbelegt werden.',
   'The invoices have been created. They\'re pre-selected below.' => 'Die Rechnungen wurden erzeugt. Sie sind unten vorausgewählt.',
   'The item couldn\'t be deleted!' => 'Der Artikel konnte nicht gelöscht werden!',
@@ -3558,8 +3688,10 @@ $self->{texts} = {
   'The partnumber is missing.'  => 'Die Artikelnummer fehlt.',
   'The parts for this delivery order have already been transferred in.' => 'Die Artikel dieses Lieferscheins wurden bereits eingelagert.',
   'The parts for this delivery order have already been transferred out.' => 'Die Artikel dieses Lieferscheins wurden bereits ausgelagert.',
+  'The parts for this order have already been transferred' => 'Die Artikel in diesem Lieferschein wurden schon umgelagert',
   'The parts have been removed.' => 'Die Waren wurden aus dem Lager entnommen.',
   'The parts have been transferred.' => 'Die Waren wurden umgelagert.',
+  'The partsgroup is missing.'  => 'Die Warengruppe fehlt.',
   'The password is too long (maximum length: #1).' => 'Das Passwort ist zu lang (maximale Länge: #1).',
   'The password is too short (minimum length: #1).' => 'Das Password ist zu kurz (minimale Länge: #1).',
   'The password is weak (e.g. it can be found in a dictionary).' => 'Das Passwort ist schwach (z.B. wenn es in einem Wörterbuch steht).',
@@ -3762,10 +3894,14 @@ $self->{texts} = {
   'This group is valid for the following clients' => 'Diese Gruppe ist für die folgenden Mandanten gültig',
   'This has been changed in this version, therefore please change the "old" bins to some real warehouse bins.' => 'Das wurde in dieser Version umgestellt, bitte ändern Sie die Freitext-Lagerplätze auf vorhandene Lagerplätze.',
   'This has been changed in this version.' => 'Ab dieser Version ist dies nicht mehr so.',
+  'This invoice has a further invoice for advanced payment.' => 'Diese Rechnung hat eine weitere Anzahlungsrechnung.',
+  'This invoice has already a final invoice.' => 'Diese Rechnung hat schon eine Schlussrechnung.',
+  'This invoice has already a further invoice for advanced payment.' => 'Diese Rechnung hat schon eine weitere Anzahlungsrechnung.',
   'This invoice has already been posted.' => 'Die Rechnung wurde bereits gebucht.',
   'This invoice has been canceled already.' => 'Die Rechnung wurde bereits storniert.',
   'This invoice has been linked with a sepa export, undo this first.' => 'Diese Rechnung ist mit einem SEPA-Export verknüpft. Bitte diese Verknüpfung zuerst aufheben.',
   'This invoice has not been posted yet.' => 'Die Rechnung wurde noch nicht gebucht.',
+  'This invoice was added from an order. See there.' => 'Diese Rechnung wurde aus einem Auftrag erstellt. Siehe dort.',
   'This invoice\'s dunning level: #1' => 'Mahnstufe dieser Rechnung: #1',
   'This is a very critical problem.' => 'Dieses Problem ist sehr schwerwiegend.',
   'This is the client to be selected by default on the login screen.' => 'Dies ist derjenige Mandant, der im Loginbildschirm standardmäßig ausgewählt sein wird.',
@@ -3782,10 +3918,12 @@ $self->{texts} = {
   'This option controls the method used for determining the startdate for the balance report.' => 'Diese Option bestimmt, wie das Startdatum für den Bilanzbericht ermittelt wird',
   'This option controls the method used for profit determination.' => 'Dieser Parameter legt die Berechnungsmethode für die Gewinnermittlung fest.',
   'This option controls the posting and calculation behavior for the accounting method.' => 'Dieser Parameter steuert die Buchungs- und Berechnungsmethoden für die Versteuerungsart.',
+  'This order has already a final invoice.' => 'Dieser Auftrag hat schon eine Schlussrechnung.',
   'This part has already been added.' => 'Dieser Artikel wurde schon hinzugefügt',
   'This part was already counted for this bin:' => 'Dieser Artikel wurde für diesen Lagerplatz bereits erfasst:',
   'This price has since gone down' => 'Dieser Preis ist mittlerweile niedriger',
   'This price has since gone up' => 'Dieser Preis ist mittlerweile höher',
+  'This record containts obsolete items at position #1' => 'Dieser Beleg enthält ungültige Artikel an Position #1',
   'This record has already been closed.' => 'Dieser Beleg wurde bereits geschlossen.',
   'This record has already been delivered.' => 'Dieser Beleg wurde bereits geliefert.',
   'This record has not been saved yet.' => 'Der Beleg wurde noch nicht gespeichert.',
@@ -3798,13 +3936,17 @@ $self->{texts} = {
   'This sales order has an active configuration for periodic invoices. If you save then all subsequently created invoices will contain those changes as well, but not those that have already been created. Do you want to continue?' => 'Dieser Auftrag besitzt eine aktive Konfiguration für wiederkehrende Rechnungen. Wenn Sie jetzt speichern, so werden alle zukünftig hieraus erzeugten Rechnungen die Änderungen enthalten, nicht aber die bereits erzeugten Rechnungen. Möchten Sie speichern?',
   'This status output will be refreshed every five seconds.' => 'Diese Statusausgabe wird alle fünf Sekunden aktualisiert.',
   'This transaction has to be split into several transactions manually.' => 'Diese Buchung muss manuell in mehrere Buchungen aufgeteilt werden.',
+  'This transaction is linked with a AP transaction. Please undo and redo the AP transaction booking if needed.' => 'Diese Buchung ist mit einer Kreditorenbuchung verknüpft. Bitte Löschen oder Ändern Sie die Kreditorenbuchung nötigenfalls.',
   'This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.' => 'Ein oder mehrere Zahlungen des Belegs sind über das Verbuchen von Kontoauszüge erstellt worden, falls notwendig kann eine Neuverbuchung über Zahlungsverkehr -> Bericht Bankbewegung möglich gemacht werden.',
+  'This transaction is linked with a gl transaction. Please delete the ap transaction booking if needed.' => 'Diese Buchung ist mit einer Dialogbuchung verknüpft. Bitte Löschen oder Ändern Sie diese Kreditorenbuchung nötigenfalls.',
+  'This transaction is reconciled with a bank transaction. Please undo the reconciliation if needed.' => 'Diese Buchung ist mit einer Bankbewegung abgeglichen. Falls die Buchung geändert werden soll, muss der Abgleich mit der Bankbewegung zuerst aufgelöst werden.',
   'This update will change the nature the onhand of goods is tracked.' => 'Dieses update ändert die Art und Weise wie Lagermengen gezält werden.',
   'This user is a member in the following groups' => 'Dieser Benutzer ist Mitglied in den folgenden Gruppen',
   'This user will have access to the following clients' => 'Dieser Benutzer wird Zugriff auf die folgenden Mandanten haben',
   'This vendor has already a booking with this invoice number, do you really want to add the same invoice number again?' => 'Es gibt für diesen Lieferant schon einen Beleg mit dieser Rechnungsnummer. Möchten Sie wirklich eine weitere Buchung mit derselben Rechnungsnummer hinzufügen?',
   'This vendor has already been added.' => 'Der Lieferant wurde bereits hinzugefügt.',
   'This vendor number is already in use.' => 'Diese Lieferantennummer wird bereits verwendet.',
+  'This will also remove this pricegroup for all customers.' => 'Damit werden auch alle verknüpften Preisgruppen im Kundenstamm gelöscht!',
   'This will apply a 3% reduction to the master data price before entering it into the record item.' => 'Diese Zeile zieht vom Stammdatenpreis 3% ab, und schlägt den resultierenden Preis vor.',
   'This will be treated as a discount in percent points.' => 'Diese Option schlägt den Wert in Prozentpunkten als Rabatt vor.',
   'This will happen before the price is offered, and the reduction will not be printed in documents.' => 'Das passiert, bevor der Preis vorgeschlagen wird, und der Abschlag wird nicht in Belegen ausgewiesen.',
@@ -3858,6 +4000,7 @@ $self->{texts} = {
   'Transaction'                 => 'Buchung',
   'Transaction %d cancelled.'   => 'Buchung %d erfolgreich storniert.',
   'Transaction Date missing!'   => 'Buchungsdatum fehlt!',
+  'Transaction Description is not yet implemented' => 'Vorgangsbezeichnung ist noch nicht implementiert',
   'Transaction ID missing.'     => 'Die Buchungs-ID fehlt.',
   'Transaction Value'           => 'Umsatz',
   'Transaction Value Currency Code' => 'WKZ Umsatz',
@@ -3893,6 +4036,7 @@ $self->{texts} = {
   'Transfer out via default'    => 'Auslagern über Standard-Lagerplatz',
   'Transfer qty'                => 'Umlagermenge',
   'Transfer services via default' => 'Falls Ein- /Auslagern über Standardlagerplatz aktiviert ist, auch die Dienstleistungen standardmässig Ein- und Auslagern',
+  'Transfer stock'              => 'Lagerbewegungen',
   'Transfer successful'         => 'Lagervorgang erfolgreich',
   'Transfer undone.'            => 'Zurücklagerung erfolgreich',
   'Transferred'                 => 'Übernommen',
@@ -3961,7 +4105,6 @@ $self->{texts} = {
   'Until'                       => 'Bis',
   'Update'                      => 'Erneuern',
   'Update Discount'             => 'Rabatt übernehmen',
-  'Update Partnumber'           => 'Update Artikel',
   'Update Price'                => 'Preis übernehmen',
   'Update Prices'               => 'Preise aktualisieren',
   'Update SKR04: new tax account 3804 (19%)' => 'Update SKR04: neues Steuerkonto 3804 (19%) für innergemeinschaftlichen Erwerb',
@@ -4006,6 +4149,8 @@ $self->{texts} = {
   'Use File Storage backend'    => 'Verwende Dateisystem-Backend',
   'Use Filemanagement'          => 'Verwende Dateimanagement',
   'Use Income'                  => 'GUV und BWA verwenden',
+  'Use Long Description from Parts for Shop Long Description' => 'Verwende den Artikel Langtext aus den Stammdaten für den Langtext im Shop',
+  'Use Long Description from Parts is only for Shopware6 implemented' => 'Der Langtext aus den Stammdaten kann nur in Shopware6 verwendet werden',
   'Use UStVA'                   => 'UStVA verwenden',
   'Use WebDAV Repository'       => 'Verwende WebDAV',
   'Use WebDAV Storage backend'  => 'Verwende WebDAV-Backend',
@@ -4018,6 +4163,7 @@ $self->{texts} = {
   'Use default booking group because wanted is missing' => 'Fehlende Buchungsgruppe, deshalb Standardbuchungsgruppe',
   'Use existing templates'      => 'Vorhandene Druckvorlagen verwenden',
   'Use for Factur-X/ZUGFeRD'    => 'Nutzung mit Factur-X/ZUGFeRD',
+  'Use for Swiss QR-Bill'       => 'Nutzung mit Schweizer QR-Rechnung',
   'Use master default bin for Default Transfer, if no default bin for the part is configured' => 'Standardlagerplatz für Ein- / Auslagern über Standard-Lagerplatz, falls für die Ware kein expliziter Lagerplatz konfiguriert ist',
   'Use settings from client configuration' => 'Einstellungen aus Mandantenkonfiguration folgen',
   'Use text field for department of contacts' => 'Textfeld für Abteilungen von Ansprechpersonen verwenden',
@@ -4084,10 +4230,18 @@ $self->{texts} = {
   'Version'                     => 'Version',
   'Version actions'             => 'Aktionen für Versionen',
   'Version number'              => 'Versionsnummer',
-  'Version: '                   => 'Version',
   'Versions'                    => 'Versionen',
+  'View RFQs'                   => 'Lieferantenanfragen ansehen',
   'View SEPA export'            => 'SEPA-Export-Details ansehen',
   'View background job execution result' => 'Verlauf der Hintergrund-Job-Ausführungen anzeigen',
+  'View purchase delivery orders' => 'Einkaufslieferscheine ansehen',
+  'View purchase invoices'      => 'Einkaufsrechungen ansehen',
+  'View purchase orders'        => 'Lieferantenaufträge ansehen',
+  'View record links from Sales Order' => 'Verknüpfte Belege immer vom Verkaufsauftrag ansehen',
+  'View sales delivery orders'  => 'Verkaufslieferscheine ansehen',
+  'View sales invoices and credit notes' => 'Rechnungen und Gutschriften ansehen',
+  'View sales orders'           => 'Auftragsbestätigungen ansehen',
+  'View sales quotations'       => 'Angebote ansehen',
   'View sent email'             => 'Verschickte E-Mail anzeigen',
   'View warehouse content'      => 'Lagerbestand ansehen',
   'View/edit all employees purchase documents' => 'Bearbeiten/ansehen der Einkaufsdokumente aller Mitarbeiter',
@@ -4107,6 +4261,7 @@ $self->{texts} = {
   'Warehouses'                  => 'Lager',
   'Warn before saving orders with duplicate parts (new controller only)' => 'Beim Speichern warnen, wenn doppelte Artikel in einem Auftrag sind',
   'Warn before saving orders without a delivery date' => 'Warnung ausgeben, falls Aufträge kein Lieferdatum haben.',
+  'Warn before saving sales orders with missing customer order number (new controller only)' => 'Warnung ausgeben, falls Verkaufsaufträge keine Kundenbestellnummer haben',
   'Warning'                     => 'Warnung',
   'Warning! Loading a draft will discard unsaved data!' => 'Achtung! Beim Laden eines Entwurfs werden ungespeicherte Daten verworfen!',
   'Warning: Faulty position ignored' => 'Warnung: Fehlerhafte Artikel-Position ignoriert',
@@ -4133,6 +4288,7 @@ $self->{texts} = {
   'What this template contains' => 'Was diese Vorlage enthält',
   'What type of item is this?'  => 'Was ist dieser Artikel?',
   'When converting a requirement spec into a quotation or an oder each section gets converted into a line position in the new record. This is the article used by default for this conversion.' => 'Wenn ein Pflichtenheft in ein Angebot oder Auftrag umgewandelt wird, wird für jeden Abschnitt eine Position im neuen Beleg angelegt. Dies ist der Artikel, der standardmäßig bei dieser Umwandlung genutzt wird.',
+  'Whether or not to replace variable placeholders such as "<%invdate%>" in texts in positions such as the part description by the record\'s actual value' => 'Ob Variablenplatzhalter wie z.B. <%invdate%> in Positionstexten wie der Artikelbeschreibung durch den tatsächlichen Wert aus dem Beleg ersetzt werden sollen',
   'Which is located at doc/kivitendo-Dokumentation.pdf. Click here: ' => 'Diese befindet sich unter doc/kivitendo-Dokumentation.pdf. Klicken Sie hier:',
   'With Attachments'            => 'Journal mit Anhängen',
   'With Extension Of Time'      => 'mit Dauerfristverlängerung',
@@ -4293,7 +4449,6 @@ $self->{texts} = {
   'delivered'                   => 'geliefert',
   'deliverydate'                => 'Lieferdatum',
   'difference as skonto'        => 'Differenz als Skonto',
-  'difference_as_skonto'        => 'Differenz als Skonto',
   'direct debit'                => 'Lastschrifteinzug',
   'disposed'                    => 'Entsorgung',
   'disposed_br'                 => 'Entsgt.',
@@ -4322,6 +4477,7 @@ $self->{texts} = {
   'filename'                    => 'Dateiname',
   'filename has not uploadable characters ' => 'Bitte Dateinamen ändern. Er hat für den Upload nicht verwendbare Sonderzeichen ',
   'filesize too big: '          => 'Datei zu groß: ',
+  'final_invoice'               => 'Schlussrechnung',
   'flat-rate position'          => 'Pauschalposition',
   'follow_up_list'              => 'wiedervorlageliste',
   'for'                         => 'für',
@@ -4348,6 +4504,7 @@ $self->{texts} = {
   'internal error (see details)' => 'Interner Fehler (siehe Details)!',
   'invoice'                     => 'Rechnung',
   'invoice mode or item mode'   => 'Rechnungsmodus oder Artikelmodus',
+  'invoice_for_advance_payment' => 'Anzahlungsrechnung',
   'invoice_list'                => 'debitorenbuchungsliste',
   'is'                          => 'ist',
   'is after'                    => 'ist nach dem',
@@ -4373,6 +4530,8 @@ $self->{texts} = {
   'list_of_receipts'            => 'zahlungseingaenge',
   'list_of_transactions'        => 'buchungsliste',
   'male'                        => 'männlich',
+  'mark as paid'                => 'als bezahlt markieren',
+  'mebil - Mapping: values for #1' => 'mebil - Mapping: Werte für #1',
   'max filesize'                => 'maximale Dateigröße',
   'min'                         => 'min',
   'missing'                     => 'Fehlbestand',
@@ -4452,6 +4611,7 @@ $self->{texts} = {
   'return_material'             => 'Materialrückgabe',
   'revert deleted'              => 'löschen rückgängig',
   'rfq_list'                    => 'anfragenliste',
+  'rma_delivery_order_list'     => 'lieferscheinliste_rma',
   'running'                     => 'läuft',
   'sales tax identification number' => 'USt-IdNr.',
   'sales_delivery_order_list'   => 'lieferscheinliste_verkauf',
@@ -4481,6 +4641,7 @@ $self->{texts} = {
   'stocktaking'                 => 'Inventur',
   'succeeded'                   => 'erfolgreich',
   'sum'                         => 'Summe',
+  'supplier_delivery_order_list' => 'lieferscheinliste_beistell',
   'tax_chartaccno'              => 'Automatikkonto',
   'tax_percent'                 => 'Prozentsatz',
   'tax_rate'                    => 'Prozent',
@@ -4523,6 +4684,8 @@ $self->{texts} = {
   'warehouse_journal_list'      => 'lagerbuchungsliste',
   'warehouse_report_list'       => 'lagerbestandsliste',
   'warehouse_usage_list'        => 'Lagerentnahmeliste',
+  'will be set upon posting'    => 'wird beim Buchen vergeben',
+  'will be set upon saving'     => 'wird beim Speichern vergeben',
   'with skonto acc. to pt'      => 'mit Skonto nach ZB',
   'with_skonto_pt'              => 'mit Skonto nach ZB',
   'without skonto'              => 'ohne Skonto',
index b82440b..314fabc 100644 (file)
@@ -31,8 +31,10 @@ order=< > \n
 order=\\ <pagebreak> & \n \r " $ <bullet> % _ # ^ { } < > £ ± ² ³ ° § ® © ~ \xad \xa0 ➔ → ← ↔ ↕ | − ≤ ≥ ‐ ​ Ω μ Δ λ Ø ø ‑
 \\=\\textbackslash\s
 <pagebreak>=
-"=''
 &=\\&
+\n=\\newline\s
+\r=
+"=''
 $=\\$
 <bullet>=$\\bullet$
 %=\\%
@@ -40,41 +42,39 @@ _=\\_
 # A hash mark starts a comment; therefore the line is ignored. So use
 # its hex code instead.
 \x23=\\#
+^=\\^\\\s
 {=\\{
 }=\\}
 <=$<$
 >=$>$
 £=\\pounds\s
-\n=\\newline\s
-\r=
 ±=$\\pm$
-^=\\^\\\s
 ²=$^2$
 ³=$^3$
 °=$^\\circ$
 §=\\S\s
 ®={\\textregistered}
 ©={\\textcopyright}
+~={\\raisebox{0.5ex}{\\texttildelow}}
 \xad=\\-
+\xa0=~
 ➔=$\\rightarrow$
 →=$\\rightarrow$
 ←=$\\leftarrow$
 ↔=$\\leftrightarrow$
 ↕=$\\updownarrow$
-\xa0=~
 |={\\textbar}
 −={\\textemdash}
 ≤=$\\leq$
 ≥=$\\geq$
 ‐={}-{}
 ​={\\hspace{0pt}}
+Ω=$\\Omega$
 μ={\\textmu}
 Δ=$\\Delta$
-Ω=$\\Omega$
 λ=$\\lambda$
-ø={\\o}
 Ø={\\O}
-~={\\raisebox{0.5ex}{\\texttildelow}}
+ø={\\o}
 ‑={}-{}
 
 [Template/OpenDocument]
index 987862c..7db3e8a 100644 (file)
@@ -13,6 +13,8 @@ $self->{texts} = {
   ' Date missing!'              => '',
   ' bytes, max='                => '',
   ' missing!'                   => '',
+  '"#1" seems to be a faulty list of email addresses. After extracing addresses (#2) too many characters are left.' => '',
+  '"#1" seems to be a faulty list of email addresses. No addresses could be extracted.' => '',
   '#1 (custom variable)'        => '',
   '#1 MD'                       => '',
   '#1 additional part(s)'       => '',
@@ -174,9 +176,11 @@ $self->{texts} = {
   'Add Delivery Order'          => '',
   'Add Document from \'#1\''    => '',
   'Add Dunning'                 => '',
+  'Add Final Invoice'           => '',
   'Add Follow-Up'               => '',
   'Add Follow-Up for #1'        => '',
   'Add General Ledger Transaction' => '',
+  'Add Invoice for Advance Payment' => '',
   'Add Letter'                  => '',
   'Add Part'                    => '',
   'Add Price Factor'            => '',
@@ -186,6 +190,7 @@ $self->{texts} = {
   'Add Purchase Order'          => '',
   'Add Quotation'               => '',
   'Add RFQ'                     => '',
+  'Add RMA Delivery Order'      => '',
   'Add Request for Quotation'   => '',
   'Add Requirement Spec'        => '',
   'Add Requirement Spec Template' => '',
@@ -194,6 +199,7 @@ $self->{texts} = {
   'Add Sales Order'             => '',
   'Add Service'                 => '',
   'Add Storno Credit Note'      => '',
+  'Add Supplier Delivery Order' => '',
   'Add Transaction'             => '',
   'Add User'                    => '',
   'Add User Group'              => '',
@@ -252,11 +258,15 @@ $self->{texts} = {
   'Added sections and function blocks: #1' => '',
   'Added text blocks: #1'       => '',
   'Addition'                    => '',
+  'Additional Billing Address'  => '',
+  'Additional Billing Addresses' => '',
   'Additional articles'         => '',
   'Additional articles actions' => '',
   'Additionally the invoice is marked for direct debit and would have been checked automatically had the bank information been entered.' => '',
   'Additionally the invoice is not marked for direct debit and would have been checked automatically had the bank information been entered.' => '',
   'Address'                     => '',
+  'Address deleted.'            => '',
+  'Address is in use and was flagged invalid.' => '',
   'Administration'              => '',
   'Administration area'         => '',
   'Advance turnover tax return' => '',
@@ -277,6 +287,7 @@ $self->{texts} = {
   'All pay postings successfully imported.' => '',
   'All payments have already been posted.' => '',
   'All payments must be posted before the payment list can be downloaded.' => '',
+  'All phone numbers'           => '',
   'All price sources'           => '',
   'All reports'                 => '',
   'All the other clients will start with an empty set of WebDAV folders.' => '',
@@ -305,6 +316,7 @@ $self->{texts} = {
   'Amount BT'                   => '',
   'Amount Due'                  => '',
   'Amount and net amount are calculated by kivitendo. "verify_amount" and "verify_netamount" can be used for sanity checks.' => '',
+  'Amount has wrong format.'    => '',
   'Amount less skonto'          => '',
   'Amount payable'              => '',
   'Amount payable less discount' => '',
@@ -351,6 +363,7 @@ $self->{texts} = {
   'Assemblies'                  => '',
   'Assembly'                    => '',
   'Assembly (typeabbreviation)' => 'A',
+  'Assembly Item Qty'           => '',
   'Assembly Last Cost'          => '',
   'Assembly Number missing!'    => '',
   'Assembly creation transfers services' => '',
@@ -422,6 +435,7 @@ $self->{texts} = {
   'Balances'                    => '',
   'Balancing'                   => '',
   'Bank'                        => '',
+  'Bank Account Id Number (Swiss)' => '',
   'Bank Code'                   => '',
   'Bank Code (long)'            => '',
   'Bank Code Number'            => '',
@@ -431,6 +445,7 @@ $self->{texts} = {
   'Bank Transaction'            => '',
   'Bank Transaction is in a closed period.' => '',
   'Bank account'                => '',
+  'Bank account id number invalid. Must be 6 digits.' => '',
   'Bank accounts'               => '',
   'Bank code'                   => '',
   'Bank code of the goal/source' => '',
@@ -531,6 +546,7 @@ $self->{texts} = {
   'CSV Export successful!'      => '',
   'CSV export'                  => '',
   'CSV export -- options'       => '',
+  'CSV import: additional billing addresses' => '',
   'CSV import: ar transactions' => '',
   'CSV import: bank transactions' => '',
   'CSV import: contacts'        => '',
@@ -553,6 +569,7 @@ $self->{texts} = {
   'Cancel Accounts Payables Transaction' => '',
   'Cancel Accounts Receivables Transaction' => '',
   'Cancelling is disallowed. Either undo or balance the current payments until the open amount matches the invoice amount' => '',
+  'Cannot Post AP transaction with tax included!' => '',
   'Cannot add Booking, reason: #1 DB: #2 ' => '',
   'Cannot allocate parts.'      => '',
   'Cannot change transaction in a closed period!' => '',
@@ -568,12 +585,15 @@ $self->{texts} = {
   'Cannot delete transaction!'  => '',
   'Cannot delete vendor!'       => '',
   'Cannot find matching template for this print request. Please contact your template maintainer. I tried these: #1.' => '',
+  'Cannot get shippingOrderAddressId for #1' => '',
   'Cannot have a value in both Debit and Credit!' => '',
   'Cannot post Payment!'        => '',
   'Cannot post Receipt!'        => '',
   'Cannot post a transaction without a value!' => '',
   'Cannot post invoice and/or transfer out! Error message:' => '',
   'Cannot post invoice for a closed period!' => '',
+  'Cannot post invoice for advance payment with more than one tax' => '',
+  'Cannot post invoice for advance payment with taxincluded' => '',
   'Cannot post invoice!'        => '',
   'Cannot post payment for a closed period!' => '',
   'Cannot post payment!'        => '',
@@ -638,7 +658,6 @@ $self->{texts} = {
   'Check Details'               => '',
   'Check connectivity'          => '',
   'Check for duplicates'        => '',
-  'Check full signature'        => '',
   'Check on ap transaction'     => '',
   'Check on ar transaction'     => '',
   'Check on gl transaction'     => '',
@@ -657,6 +676,7 @@ $self->{texts} = {
   'Cleared Balance'             => '',
   'Cleared/uncleared only'      => '',
   'Clearing Tax Received (No 71)' => '',
+  'Clearing account for advance payments' => '',
   'Client'                      => '',
   'Client #1'                   => '',
   'Client Configuration'        => '',
@@ -687,6 +707,7 @@ $self->{texts} = {
   'Company name'                => '',
   'Company name and address'    => '',
   'Company settings'            => '',
+  'Company\'s email signature'  => '',
   'Compare to'                  => '',
   'Complexities'                => '',
   'Complexity'                  => '',
@@ -804,7 +825,10 @@ $self->{texts} = {
   'Create one from the context menu by right-clicking on this text.' => '',
   'Create order'                => '',
   'Create sales invoices with Factur-X/ZUGFeRD data' => '',
+  'Create sales invoices with Swiss QR-bill' => '',
   'Create tables'               => '',
+  'Create variant IBAN without reference' => '',
+  'Create variant QR-IBAN with QR reference' => '',
   'Create with profile \'Factur-X 1.0.05/ZUGFeRD 2.1.1 extended\'' => '',
   'Create with profile \'Factur-X 1.0.05/ZUGFeRD 2.1.1 extended\' (test mode)' => '',
   'Create with profile \'XRechnung 2.0.0\'' => '',
@@ -814,6 +838,7 @@ $self->{texts} = {
   'Created for'                 => '',
   'Created on'                  => '',
   'Creating Documents'          => '',
+  'Creating Factur-X/ZUGFeRD invoices is not enabled for this customer.' => '',
   'Creating invoices'           => '',
   'Creating the PDF failed:'    => '',
   'Creation Date'               => '',
@@ -855,6 +880,7 @@ $self->{texts} = {
   'Current version'             => '',
   'Current year'                => '',
   'Currently #1 delivery orders can be converted into invoices and printed.' => '',
+  'Custom Billing Address'      => '',
   'Custom CSV format'           => '',
   'Custom Variables'            => '',
   'Custom data export'          => '',
@@ -871,11 +897,13 @@ $self->{texts} = {
   'Customer Order Number'       => '',
   'Customer Part Number'        => '',
   'Customer Price'              => '',
+  'Customer Proposals'          => '',
   'Customer deleted!'           => '',
   'Customer details'            => '',
   'Customer missing!'           => '',
   'Customer must not be empty.' => '',
   'Customer not found'          => '',
+  'Customer number invalid. Must be less then or equal to 6 digits after prefix.' => '',
   'Customer of assigned order must match customer.' => '',
   'Customer of assigned project must match customer.' => '',
   'Customer saved'              => '',
@@ -949,6 +977,7 @@ $self->{texts} = {
   'Date Paid'                   => '',
   'Date and timestamp variables: If the default value equals \'NOW\' then the current date/current timestamp will be used. Otherwise the default value is copied as-is.' => '',
   'Date missing!'               => '',
+  'Date of Last Payment'        => '',
   'Date the payment is due in full' => '',
   'Date the payment is due with discount' => '',
   'Datev export encoding'       => '',
@@ -974,6 +1003,7 @@ $self->{texts} = {
   'Decrease'                    => '',
   'Default (no language selected)' => '',
   'Default Accounts'            => '',
+  'Default Billing Address'     => '',
   'Default Bin'                 => '',
   'Default Bin with ignoring onhand' => '',
   'Default Client (unconfigured)' => '',
@@ -985,6 +1015,7 @@ $self->{texts} = {
   'Default Transfer with services' => '',
   'Default Warehouse'           => '',
   'Default Warehouse with ignoring onhand' => '',
+  'Default address flag'        => '',
   'Default article for converting into quotations and orders' => '',
   'Default booking group'       => '',
   'Default client'              => '',
@@ -1011,7 +1042,9 @@ $self->{texts} = {
   'Delete Documents'            => '',
   'Delete Images'               => '',
   'Delete Shipto'               => '',
+  'Delete address'              => '',
   'Delete all'                  => '',
+  'Delete for Customers'        => '',
   'Delete links'                => '',
   'Delete picture'              => '',
   'Delete printfiles'           => '',
@@ -1031,8 +1064,11 @@ $self->{texts} = {
   'Delivery Order Date'         => '',
   'Delivery Order Date missing!' => '',
   'Delivery Order Number'       => '',
+  'Delivery Order Type'         => '',
   'Delivery Order created'      => '',
   'Delivery Order deleted!'     => '',
+  'Delivery Order has been deleted' => '',
+  'Delivery Order has been saved' => '',
   'Delivery Order(s) for full qty created' => '',
   'Delivery Orders'             => '',
   'Delivery Plan'               => '',
@@ -1094,6 +1130,7 @@ $self->{texts} = {
   'Do not change the tax rate of taxkey 0.' => '',
   'Do not check for duplicates' => '',
   'Do not create Factur-X/ZUGFeRD invoices' => '',
+  'Do not create QR-bill invoices' => '',
   'Do not leave booking form?'  => '',
   'Do not link to a project.'   => '',
   'Do not modify this position' => '',
@@ -1120,6 +1157,7 @@ $self->{texts} = {
   'Do you really want to mark the selected entries as booked?' => '',
   'Do you really want to print?' => '',
   'Do you really want to revert to this version?' => '',
+  'Do you really want to transfer the stock and set this order to delivered?' => '',
   'Do you really want to undo the selected SEPA exports? You have to reassign the export again.' => '',
   'Do you really want to unimport the selected documents?' => '',
   'Do you want to <b>limit</b> your search?' => '',
@@ -1220,9 +1258,11 @@ $self->{texts} = {
   'Edit Dunning Process Config' => '',
   'Edit Employee #1'            => '',
   'Edit Factur-X/ZUGFeRD notes' => '',
+  'Edit Final Invoice'          => '',
   'Edit Follow-Up'              => '',
   'Edit Follow-Up for #1'       => '',
   'Edit General Ledger Transaction' => '',
+  'Edit Invoice for Advance Payment' => '',
   'Edit Letter'                 => '',
   'Edit Part'                   => '',
   'Edit Preferences for #1'     => '',
@@ -1231,6 +1271,7 @@ $self->{texts} = {
   'Edit Purchase Delivery Order' => '',
   'Edit Purchase Order'         => '',
   'Edit Quotation'              => '',
+  'Edit RMA Delivery Order'     => '',
   'Edit Request for Quotation'  => '',
   'Edit SEPA strings'           => '',
   'Edit Sales Delivery Order'   => '',
@@ -1239,6 +1280,8 @@ $self->{texts} = {
   'Edit Service'                => '',
   'Edit Storno Credit Note'     => '',
   'Edit Storno Invoice'         => '',
+  'Edit Storno Invoice for Advance Payment' => '',
+  'Edit Supplier Delivery Order' => '',
   'Edit User'                   => '',
   'Edit User Group'             => '',
   'Edit Vendor'                 => '',
@@ -1305,14 +1348,15 @@ $self->{texts} = {
   'Edit time recordings of all staff members' => '',
   'Edit title'                  => '',
   'Edit units'                  => '',
-  'Edit user signature'         => '',
   'Editable'                    => '',
   'Either there are no open invoices, or you have already initiated bank transfers with the open amounts for those that are still open.' => '',
   'Element disabled'            => '',
   'Email'                       => '',
+  'Email address'               => '',
   'Email journal'               => '',
   'Email of the delivery order recipient' => '',
   'Email of the invoice recipient' => '',
+  'Email signature'             => '',
   'Employee'                    => '',
   'Employee #1 saved!'          => '',
   'Employee (database ID)'      => '',
@@ -1336,17 +1380,21 @@ $self->{texts} = {
   'Equity'                      => '',
   'Erfolgsrechnung'             => '',
   'Error'                       => '',
+  'Error getting QR-Bill type.' => '',
   'Error handling'              => '',
   'Error in database control file \'%s\': %s' => '',
   'Error in position #1: You must either assign no stock at all or the full quantity of #2 #3.' => '',
   'Error in position #1: You must either assign no transfer at all or the full quantity of #2 #3.' => '',
   'Error in row #1: The quantity you entered is bigger than the stocked quantity.' => '',
+  'Error mapping biller countrycode.' => '',
+  'Error mapping customer countrycode.' => '',
   'Error message from the database driver:' => '',
   'Error message from the database: #1' => '',
   'Error message from the webshop api:' => '',
   'Error when saving: #1'       => '',
   'Error while applying year-end bookings!' => '',
   'Error while creating project with project number of new order number, project number #1 already exists!' => '',
+  'Error while saving shop order #1. DB Error #2. Generic exception #3.' => '',
   'Error with default taxzone'  => '',
   'Error!'                      => '',
   'Error: #1'                   => '',
@@ -1459,6 +1507,7 @@ $self->{texts} = {
   'Existing contacts (with column \'cp_id\')' => '',
   'Existing customers/vendors with same customer/vendor number' => '',
   'Existing file on server'     => '',
+  'Existing finished follow-ups for this item' => '',
   'Existing pending follow-ups for this item' => '',
   'Existing profiles'           => '',
   'Existing templates'          => '',
@@ -1486,6 +1535,7 @@ $self->{texts} = {
   'Extended status'             => '',
   'Extension Of Time'           => '',
   'Factor'                      => '',
+  'Factur-X/ZUGFeRD'            => '',
   'Factur-X/ZUGFeRD import'     => '',
   'Factur-X/ZUGFeRD invoice'    => '',
   'Factur-X/ZUGFeRD notes for each invoice' => '',
@@ -1495,6 +1545,7 @@ $self->{texts} = {
   'Feb'                         => '',
   'February'                    => '',
   'Fee'                         => '',
+  'Fetch from last order number is not implemented' => '',
   'Fetch order'                 => '',
   'Field'                       => '',
   'File'                        => '',
@@ -1519,6 +1570,9 @@ $self->{texts} = {
   'Filter for item variables'   => '',
   'Filter parts'                => '',
   'Filter record template'      => '',
+  'Final Invoice'               => '',
+  'Final Invoice (one letter abbreviation)' => '',
+  'Final Invoice, please use mark as paid manually' => '',
   'Financial Controlling'       => '',
   'Financial Controlling Report' => '',
   'Financial Overview'          => '',
@@ -1555,6 +1609,7 @@ $self->{texts} = {
   'For part "#1" there is no default warehouse and bin for ignoring onhand defined.' => '',
   'For purchase delivery orders, warn on workflow to invoice if not stocked in' => '',
   'For sales delivery orders, warn on workflow to invoice if not stocked out' => '',
+  'For sales invoices, warn if invoice has no delivery order as a predecessor' => '',
   'For type "customer" the perl module JSON is required. Please check this on system level: $ ./scripts/installation_check.pl' => '',
   'Foreign Exchange Gain'       => '',
   'Foreign Exchange Loss'       => '',
@@ -1580,11 +1635,13 @@ $self->{texts} = {
   'Front page'                  => '',
   'Full Access'                 => '',
   'Full Preview'                => '',
+  'Full Text'                   => '',
   'Full access to all functions' => '',
   'Function block'              => '',
   'Function block actions'      => '',
   'Function block number format' => '',
   'Function/position'           => '',
+  'Further Invoice for Advance Payment' => '',
   'GL Transaction'              => '',
   'GL Transaction (abbreviation)' => '',
   'GL Transactions'             => '',
@@ -1604,6 +1661,7 @@ $self->{texts} = {
   'General ledger transactions can only be changed on the day they are posted.' => '',
   'General settings'            => '',
   'Generate and print sales delivery orders' => '',
+  'Generating the document failed: #1' => '',
   'Germany'                     => '',
   'Get one order'               => '',
   'Get one order by shopordernumber' => '',
@@ -1627,6 +1685,7 @@ $self->{texts} = {
   'Groups valid for this client' => '',
   'HTML'                        => '',
   'HTML Templates'              => '',
+  'HTML field'                  => '',
   'Handling of WebDAV'          => '',
   'Hardcopy'                    => '',
   'Has item type'               => '',
@@ -1683,14 +1742,21 @@ $self->{texts} = {
   'If disabled purchase invoices can only be created by conversion from existing requests for quotations, purchase orders and purchase delivery orders.' => '',
   'If disabled sales orders cannot be converted into sales invoices directly.' => '',
   'If disabled sales quotations cannot be converted into sales invoices directly.' => '',
+  'If disabled, record numbers for sales records & purchase records produced by our side will always be auto-generated and cannot be changed later.' => '',
   'If enabled Factur-X/ZUGFeRD conformant sales invoice PDFs will be created.' => '',
   'If enabled a column will be shown in sales and purchase orders that lists both the amount and the value not shipped yet for each item.' => '',
+  'If enabled a warning will be shown if a sales invoices is created without having a sales delivery order as a predecessor.' => '',
   'If enabled a warning will be shown in purchase delivery orders on workflow to invoices if positions are not stocked in.' => '',
   'If enabled a warning will be shown in sales and purchase orders if there are two or more positions of the same part (new controller only).' => '',
   'If enabled a warning will be shown in sales and purchase orders if there the delivery date is empty.' => '',
+  'If enabled a warning will be shown in sales delivery orders if the customer order number is missing.' => '',
   'If enabled a warning will be shown in sales delivery orders on workflow to invoices if positions are not stocked out.' => '',
   'If enabled only those projects that are assigned to the currently selected customer are offered for selection in sales records.' => '',
   'If enabled purchase and sales records cannot be saved if no transaction description has been entered.' => '',
+  'If enabled sales invoices created using OpenDocument/OASIS format will include data for Swiss QR-Bill creation.' => '',
+  'If enabled the record links view starts always from the sales order including all sublevels' => '',
+  'If enabled try to overrule the brower\'s back button to prevent double booking of sales invoices.' => '',
+  'If enabled, when saving parts the partsgroup must be not be empty.' => '',
   'If item not found, allow creation of new item' => '',
   'If left empty the default sender from the kivitendo configuration will be used (key \'email_from\' in section \'periodic_invoices\'; current value: #1).' => '',
   'If missing then the start date will be used.' => '',
@@ -1788,6 +1854,7 @@ $self->{texts} = {
   'Internal Phone List'         => '',
   'Internal comment'            => '',
   'Internet'                    => '',
+  'Interpolate variables in texts of positions' => '',
   'Into bin'                    => '',
   'Intra-Community supply'      => '',
   'Introduction of clients'     => '',
@@ -1801,6 +1868,7 @@ $self->{texts} = {
   'Invalid follow-up ID.'       => '',
   'Invalid quantity.'           => '',
   'Invalid request type \'#1\'' => '',
+  'Invalid todo for updating Part' => '',
   'Invalid transactions'        => '',
   'Invalid variable #1'         => '',
   'Invdate'                     => '',
@@ -1816,6 +1884,7 @@ $self->{texts} = {
   'Invnumber missing!'          => '',
   'Invoice'                     => '',
   'Invoice (one letter abbreviation)' => '',
+  'Invoice Copy'                => '',
   'Invoice Date'                => '',
   'Invoice Date missing!'       => '',
   'Invoice Duedate'             => '',
@@ -1828,9 +1897,13 @@ $self->{texts} = {
   'Invoice email and Contact Person' => '',
   'Invoice email settings'      => '',
   'Invoice filter'              => '',
+  'Invoice for Advance Payment' => '',
+  'Invoice for Advance Payment (one letter abbreviation)' => '',
+  'Invoice for Advance Payment with Storno (abbreviation)' => '',
   'Invoice for fees'            => '',
   'Invoice has already been storno\'d!' => '',
   'Invoice number'              => '',
+  'Invoice number invalid. Must be less then or equal to 7 digits after prefix.' => '',
   'Invoice to:'                 => '',
   'Invoice total'               => '',
   'Invoice total less discount' => '',
@@ -1840,7 +1913,6 @@ $self->{texts} = {
   'Invoices with payments cannot be canceled.' => '',
   'Invoices, Credit Notes & AR Transactions' => '',
   'Is Searchable'               => '',
-  'Is sales'                    => '',
   'Is this a summary account to record' => '',
   'It can be changed later but must be unique within the installation.' => '',
   'It is not allowed that a summary account occurs in a drop-down menu!' => '',
@@ -1911,6 +1983,7 @@ $self->{texts} = {
   'Lastcost'                    => '',
   'Lastcost (with X being a number)' => '',
   'Lastname'                    => '',
+  'Leading and trailing whitespaces have been removed.' => '',
   'Left'                        => '',
   'Letter'                      => '',
   'Letter Draft'                => '',
@@ -1975,6 +2048,7 @@ $self->{texts} = {
   'Long Description (quotations & orders)' => '',
   'Long Description for invoices' => '',
   'Long Description for quotations & orders' => '',
+  'Longdescription dialog size percentage from main window (0 means fix values)' => '',
   'Loss'                        => '',
   'Loss carried forward account' => '',
   'Luxembourg'                  => '',
@@ -2078,6 +2152,9 @@ $self->{texts} = {
   'Name does not make sense without any bsooqr options' => '',
   'Name in Selected Records'    => '',
   'Name of the goal/source (if field names remote_name and remote_name_1 exist they will be combined into field "remote_name")' => '',
+  'Need a image title'          => '',
+  'Need a valid Shop Part for updating Part' => '',
+  'Need a workflow for Supplier Delivery Order' => '',
   'Need at least one original position for the workflow Order to Delivery Order!' => '',
   'Need charge number!'         => '',
   'Negative reductions are possible to model price increases.' => '',
@@ -2097,6 +2174,7 @@ $self->{texts} = {
   'New Password'                => '',
   'New Purchase Price Rule'     => '',
   'New Sales Price Rule'        => '',
+  'New address'                 => '',
   'New client #1: The database configuration fields "host", "port", "name" and "user" must not be empty.' => '',
   'New client #1: The name must be unique and not empty.' => '',
   'New contact'                 => '',
@@ -2117,16 +2195,20 @@ $self->{texts} = {
   'No 1:n or n:1 relation'      => '',
   'No AP Record Template for this vendor found, please add one' => '',
   'No AP template was found.'   => '',
+  'No Billing and ship to address, for Order Number #1 with ID Billing #2 and ID Shipping #3' => '',
   'No Company Address given'    => '',
   'No Company Name given'       => '',
   'No Customer was found matching the search parameters.' => '',
   'No GL template was found.'   => '',
   'No Journal'                  => '',
+  'No Order Number'             => '',
+  'No Order items fetched'      => '',
   'No Shopdescription'          => '',
   'No Shopimages'               => '',
   'No VAT Info for this Factur-X/ZUGFeRD invoice, please ask your vendor to add this for his Factur-X/ZUGFeRD data.' => '',
   'No Vendor was found matching the search parameters.' => '',
   'No action defined.'          => '',
+  'No address selected to delete' => '',
   'No article has been selected yet.' => '',
   'No articles have been added yet.' => '',
   'No assembly has been selected yet.' => '',
@@ -2134,8 +2216,10 @@ $self->{texts} = {
   'No bank account chosen!'     => '',
   'No bank account configured for bank code/BIC #1, account number/IBAN #2.' => '',
   'No bank account flagged for Factur-X/ZUGFeRD usage was found.' => '',
+  'No bank account flagged for QRBill usage was found.' => '',
   'No bank information has been entered in this customer\'s master data entry. You cannot create bank collections unless you enter bank information.' => '',
   'No bank information has been entered in this vendor\'s master data entry. You cannot create bank transfers unless you enter bank information.' => '',
+  'No billing city'             => '',
   'No bins have been added to this warehouse yet.' => '',
   'No carry-over chart configured!' => '',
   'No changes since previous version.' => '',
@@ -2143,6 +2227,7 @@ $self->{texts} = {
   'No contact selected to delete' => '',
   'No contra account selected!' => '',
   'No custom data exports have been created yet.' => '',
+  'No customer email'           => '',
   'No customer has been selected yet.' => '',
   'No customer selected or found!' => '',
   'No data was found.'          => '',
@@ -2185,8 +2270,10 @@ $self->{texts} = {
   'No sections created yet'     => '',
   'No sections have been created so far.' => '',
   'No sections have been created yet.' => '',
+  'No shipto city'              => '',
   'No shipto selected to delete' => '',
   'No start date given, setting to #1' => '',
+  'No stock to transfer'        => '',
   'No such job #1 in the database.' => '',
   'No summary account'          => '',
   'No superuser credentials were entered.' => '',
@@ -2220,6 +2307,7 @@ $self->{texts} = {
   'Not done yet'                => '',
   'Not enough in stock for the serial number #1' => '',
   'Not obsolete'                => '',
+  'Not yet implemented'         => '',
   'Note'                        => '',
   'Note that parameter names must not be quoted.' => '',
   'Note: Taxkeys must have a "valid from" date, and will not behave correctly without.' => '',
@@ -2285,6 +2373,7 @@ $self->{texts} = {
   'Oops. No valid action found to dispatch. Please report this case to the kivitendo team.' => '',
   'Open'                        => '',
   'Open Amount'                 => '',
+  'Open Amount at Last Payment Date' => '',
   'Open Items'                  => '',
   'Open Orders'                 => '',
   'Open a further kivitendo window or tab' => '',
@@ -2309,6 +2398,7 @@ $self->{texts} = {
   'Order amount'                => '',
   'Order deleted!'              => '',
   'Order item search'           => '',
+  'Order number invalid. Must be less then or equal to 7 digits after prefix.' => '',
   'Order probability'           => '',
   'Order probability & expected billing date' => '',
   'Order value periodicity'     => '',
@@ -2320,6 +2410,7 @@ $self->{texts} = {
   'Orders'                      => '',
   'Orders / Delivery Orders deleteable' => '',
   'Orders to fetch'             => '',
+  'Orders to fetch neeeds a positive Integer' => '',
   'Orientation'                 => '',
   'Orig. Size w/h'              => '',
   'Origin of personal data'     => '',
@@ -2371,6 +2462,7 @@ $self->{texts} = {
   'Part (typeabbreviation)'     => 'P',
   'Part Classification'         => '',
   'Part Description'            => '',
+  'Part Description is too long for this Shopware version. It should have lower than 255 characters.' => '',
   'Part Description missing!'   => '',
   'Part Notes'                  => '',
   'Part Number'                 => '',
@@ -2397,6 +2489,7 @@ $self->{texts} = {
   'Partsgroup'                  => '',
   'Partsgroup (database ID)'    => '',
   'Partsgroup (name)'           => '',
+  'Partsgroup is required for parts' => '',
   'Partsgroups'                 => '',
   'Partsgroups where variables are shown' => '',
   'Password'                    => '',
@@ -2438,8 +2531,14 @@ $self->{texts} = {
   'Perpetual inventory'         => '',
   'Personal settings'           => '',
   'Phone'                       => '',
+  'Phone Notes'                 => '',
   'Phone extension'             => '',
   'Phone extension missing in user configuration' => '',
+  'Phone note has been created.' => '',
+  'Phone note has been deleted.' => '',
+  'Phone note has been updated.' => '',
+  'Phone note needs a subject and a body.' => '',
+  'Phone note not found for this order.' => '',
   'Phone password'              => '',
   'Phone password missing in user configuration' => '',
   'Phone1'                      => '',
@@ -2540,6 +2639,7 @@ $self->{texts} = {
   'Preset email text for sales invoices with direct debit' => '',
   'Preset email text for sales orders' => '',
   'Preset email text for sales quotations' => '',
+  'Prevent browser\'s back button in sales invoices' => '',
   'Preview'                     => '',
   'Preview Mode'                => '',
   'Previous month'              => '',
@@ -2621,7 +2721,6 @@ $self->{texts} = {
   'Project (description)'       => '',
   'Project (number)'            => '',
   'Project Description'         => '',
-  'Project Details'             => '',
   'Project Link'                => '',
   'Project Number'              => '',
   'Project Numbers'             => '',
@@ -2641,6 +2740,7 @@ $self->{texts} = {
   'Proposal'                    => '',
   'Proposals'                   => '',
   'Protocol'                    => '',
+  'Proxy'                       => '',
   'Prozentual/Absolut'          => '',
   'Purchase'                    => 'Purchase',
   'Purchase (typeabbreviation)' => 'P',
@@ -2665,6 +2765,9 @@ $self->{texts} = {
   'Purpose'                     => '',
   'Purpose (if field names purpose, purpose1, purpose2 ... exist they will all combined into the field "purpose")' => '',
   'Purpose/Reference'           => '',
+  'QR bill without amount'      => '',
+  'QR-Code placeholder image: QRCodePlaceholder not found in template.' => '',
+  'QR-Image generation failed: ' => '',
   'QUEUED'                      => '',
   'Qty'                         => '',
   'Qty according to delivery order' => '',
@@ -2706,6 +2809,9 @@ $self->{texts} = {
   'RFQ Date'                    => '',
   'RFQ Number'                  => '',
   'RFQs'                        => '',
+  'RMA Delivery Order'          => '',
+  'RMA Delivery Orders'         => '',
+  'RMA delivery order'          => '',
   'ROP'                         => '',
   'Ranges of numbers'           => '',
   'Re-numbering all sections and function blocks in the order they are currently shown cannot be undone.' => '',
@@ -2731,6 +2837,7 @@ $self->{texts} = {
   'Record Vendor Invoice'       => '',
   'Record in'                   => '',
   'Record number'               => '',
+  'Record numbers changeable'   => '',
   'Record templates'            => '',
   'Record type to create'       => '',
   'Record\'s files'             => '',
@@ -2924,12 +3031,16 @@ $self->{texts} = {
   'Save and Close'              => '',
   'Save and Delivery Order'     => '',
   'Save and E-mail'             => '',
+  'Save and Final Invoice'      => '',
+  'Save and Further Invoice for Advance Payment' => '',
   'Save and Invoice'            => '',
+  'Save and Invoice for Advance Payment' => '',
   'Save and Order'              => '',
   'Save and Purchase Order'     => '',
   'Save and Quotation'          => '',
   'Save and RFQ'                => '',
   'Save and Sales Order'        => '',
+  'Save and Supplier Delivery Order' => '',
   'Save and close'              => '',
   'Save and execute'            => '',
   'Save and keep open'          => '',
@@ -2995,7 +3106,7 @@ $self->{texts} = {
   'Send email'                  => '',
   'Send invoice via email'      => '',
   'Send printout of record'     => '',
-  'Send the last printout created for this record' => '',
+  'Send the last or create the first version for this record' => '',
   'Sender'                      => '',
   'Sent emails can be optionally stored in the database with or without their attachments.' => '',
   'Sent on'                     => '',
@@ -3036,6 +3147,8 @@ $self->{texts} = {
   'Shipping Address'            => '',
   'Shipping Point'              => '',
   'Shipping address (name)'     => '',
+  'Shipping cost article is not implemented' => '',
+  'Shipping cost article not implemented' => '',
   'Shipping costs'              => '',
   'Shipping date'               => '',
   'Shippingcosts'               => '',
@@ -3164,6 +3277,7 @@ $self->{texts} = {
   'Skipping due to same partnumber in csv file' => '',
   'Skipping non-existent article' => '',
   'Skonto'                      => '',
+  'Skonto Tax Correction for'   => '',
   'Skonto Terms'                => '',
   'Skonto amount'               => '',
   'Skonto information'          => '',
@@ -3217,6 +3331,7 @@ $self->{texts} = {
   'Stock Qty for Date'          => '',
   'Stock for part #1'           => '',
   'Stock levels'                => '',
+  'Stock transfered'            => '',
   'Stock value'                 => '',
   'StockInfo'                   => '',
   'Stocked Qty'                 => '',
@@ -3232,6 +3347,8 @@ $self->{texts} = {
   'Storage Type for shopimages' => '',
   'Storing PDF in storage backend failed: #1' => '',
   'Storing PDF to webdav folder failed: #1' => '',
+  'Storing the document in the storage backend failed: #1' => '',
+  'Storing the document to the WebDAV folder failed: #1' => '',
   'Storing the emails in the journal is currently disabled in the client configuration.' => '',
   'Storno'                      => '',
   'Storno (one letter abbreviation)' => '',
@@ -3264,6 +3381,11 @@ $self->{texts} = {
   'Sun'                         => '',
   'Sunday'                      => '',
   'Superuser name'              => '',
+  'Supplier Delivery Order'     => '',
+  'Supplier Delivery Order has been deleted' => '',
+  'Supplier Delivery Order has been saved' => '',
+  'Supplier Delivery Orders'    => '',
+  'Supplier delivery order'     => '',
   'Supplies'                    => '',
   'Surname'                     => '',
   'Switzerland'                 => '',
@@ -3338,10 +3460,10 @@ $self->{texts} = {
   'Text blocks back'            => '',
   'Text blocks front'           => '',
   'Text field'                  => '',
-  'Text field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the text field. They default to 30 and 5 respectively.' => '',
+  'Text field and HTML field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the field in pixels. They default to 225 and 90 respectively.' => '',
   'Text in CSV File'            => '',
   'Text variables: \'MAXLENGTH=n\' sets the maximum entry length to \'n\'.' => '',
-  'Text, text field and number variables: The default value will be used as-is.' => '',
+  'Text, text field, HTML field and number variables: The default value will be used as-is.' => '',
   'Texts for invoices'          => '',
   'Texts for quotations & orders' => '',
   'That export does not exist.' => '',
@@ -3358,6 +3480,8 @@ $self->{texts} = {
   'The Factur-X/ZUGFeRD version used is not supported.' => '',
   'The GL transaction #1 has been deleted.' => '',
   'The Geierlein path has not been set in the configuration.' => '',
+  'The Host Name is missing'    => '',
+  'The Host Name seems invalid' => '',
   'The IBAN \'#1\' is not valid as IBANs in #2 must be exactly #3 characters long.' => '',
   'The IBAN is missing.'        => '',
   'The ID #1 is not a valid database ID.' => '',
@@ -3366,6 +3490,8 @@ $self->{texts} = {
   'The PDF has been created'    => '',
   'The PDF has been previewed'  => '',
   'The PDF has been printed'    => '',
+  'The Protocol for Host Name seems invalid (expected: http:// or https://)!' => '',
+  'The Proxy Name seems invalid' => '',
   'The SEPA export has been created.' => '',
   'The SEPA strings have been saved.' => '',
   'The SQL query can be parameterized with variables named as follows: <%name%>.' => '',
@@ -3451,6 +3577,7 @@ $self->{texts} = {
   'The custom variable has been saved.' => '',
   'The custom variable is in use and cannot be deleted.' => '',
   'The customer name is missing.' => '',
+  'The customer order number is missing. Do you want to continue anyway?' => '',
   'The customer\'s bank account number (IBAN) is missing.' => '',
   'The database for user management and authentication does not exist. You can create let kivitendo create it with the following parameters:' => '',
   'The database host is missing.' => '',
@@ -3479,6 +3606,8 @@ $self->{texts} = {
   'The display of (mainly) picker results can be configured. To insert the value of one option use <%Name%>.' => '',
   'The document has been changed by another user. No mail was sent. Please reopen it in another window and copy the changes to the new window' => '',
   'The document has been changed by another user. Please reopen it in another window and copy the changes to the new window' => '',
+  'The document has been created.' => '',
+  'The document has been printed.' => '',
   'The documents have been sent to the printer \'#1\'.' => '',
   'The dunnings have been printed.' => '',
   'The email has been sent.'    => '',
@@ -3515,6 +3644,7 @@ $self->{texts} = {
   'The greetings have been saved.' => '',
   'The installation is currently locked.' => '',
   'The installation is currently unlocked.' => '',
+  'The invoice is not linked with a sales delivery order. Post anyway?' => '',
   'The invoice recipient can either be a selected contact person (default) or the email adress set in the master data of the customer. Additionally a contact persons mail and the company\'s invoicing mail can be combined.' => '',
   'The invoices have been created. They\'re pre-selected below.' => '',
   'The item couldn\'t be deleted!' => '',
@@ -3557,8 +3687,10 @@ $self->{texts} = {
   'The partnumber is missing.'  => '',
   'The parts for this delivery order have already been transferred in.' => '',
   'The parts for this delivery order have already been transferred out.' => '',
+  'The parts for this order have already been transferred' => '',
   'The parts have been removed.' => '',
   'The parts have been transferred.' => '',
+  'The partsgroup is missing.'  => '',
   'The password is too long (maximum length: #1).' => '',
   'The password is too short (minimum length: #1).' => '',
   'The password is weak (e.g. it can be found in a dictionary).' => '',
@@ -3761,10 +3893,14 @@ $self->{texts} = {
   'This group is valid for the following clients' => '',
   'This has been changed in this version, therefore please change the "old" bins to some real warehouse bins.' => '',
   'This has been changed in this version.' => '',
+  'This invoice has a further invoice for advanced payment.' => '',
+  'This invoice has already a final invoice.' => '',
+  'This invoice has already a further invoice for advanced payment.' => '',
   'This invoice has already been posted.' => '',
   'This invoice has been canceled already.' => '',
   'This invoice has been linked with a sepa export, undo this first.' => '',
   'This invoice has not been posted yet.' => '',
+  'This invoice was added from an order. See there.' => '',
   'This invoice\'s dunning level: #1' => '',
   'This is a very critical problem.' => '',
   'This is the client to be selected by default on the login screen.' => '',
@@ -3781,10 +3917,12 @@ $self->{texts} = {
   'This option controls the method used for determining the startdate for the balance report.' => '',
   'This option controls the method used for profit determination.' => '',
   'This option controls the posting and calculation behavior for the accounting method.' => '',
+  'This order has already a final invoice.' => '',
   'This part has already been added.' => '',
   'This part was already counted for this bin:' => '',
   'This price has since gone down' => '',
   'This price has since gone up' => '',
+  'This record containts obsolete items at position #1' => '',
   'This record has already been closed.' => '',
   'This record has already been delivered.' => '',
   'This record has not been saved yet.' => '',
@@ -3797,13 +3935,17 @@ $self->{texts} = {
   'This sales order has an active configuration for periodic invoices. If you save then all subsequently created invoices will contain those changes as well, but not those that have already been created. Do you want to continue?' => '',
   'This status output will be refreshed every five seconds.' => '',
   'This transaction has to be split into several transactions manually.' => '',
+  'This transaction is linked with a AP transaction. Please undo and redo the AP transaction booking if needed.' => '',
   'This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.' => '',
+  'This transaction is linked with a gl transaction. Please delete the ap transaction booking if needed.' => '',
+  'This transaction is reconciled with a bank transaction. Please undo the reconciliation if needed.' => '',
   'This update will change the nature the onhand of goods is tracked.' => '',
   'This user is a member in the following groups' => '',
   'This user will have access to the following clients' => '',
   'This vendor has already a booking with this invoice number, do you really want to add the same invoice number again?' => '',
   'This vendor has already been added.' => '',
   'This vendor number is already in use.' => '',
+  'This will also remove this pricegroup for all customers.' => '',
   'This will apply a 3% reduction to the master data price before entering it into the record item.' => '',
   'This will be treated as a discount in percent points.' => '',
   'This will happen before the price is offered, and the reduction will not be printed in documents.' => '',
@@ -3857,6 +3999,7 @@ $self->{texts} = {
   'Transaction'                 => '',
   'Transaction %d cancelled.'   => '',
   'Transaction Date missing!'   => '',
+  'Transaction Description is not yet implemented' => '',
   'Transaction ID missing.'     => '',
   'Transaction Value'           => '',
   'Transaction Value Currency Code' => '',
@@ -3892,6 +4035,7 @@ $self->{texts} = {
   'Transfer out via default'    => '',
   'Transfer qty'                => '',
   'Transfer services via default' => '',
+  'Transfer stock'              => '',
   'Transfer successful'         => '',
   'Transfer undone.'            => '',
   'Transferred'                 => '',
@@ -3960,7 +4104,6 @@ $self->{texts} = {
   'Until'                       => '',
   'Update'                      => '',
   'Update Discount'             => '',
-  'Update Partnumber'           => '',
   'Update Price'                => '',
   'Update Prices'               => '',
   'Update SKR04: new tax account 3804 (19%)' => '',
@@ -4005,6 +4148,8 @@ $self->{texts} = {
   'Use File Storage backend'    => '',
   'Use Filemanagement'          => '',
   'Use Income'                  => 'Use GUV and BWA',
+  'Use Long Description from Parts for Shop Long Description' => '',
+  'Use Long Description from Parts is only for Shopware6 implemented' => '',
   'Use UStVA'                   => '',
   'Use WebDAV Repository'       => '',
   'Use WebDAV Storage backend'  => '',
@@ -4017,6 +4162,7 @@ $self->{texts} = {
   'Use default booking group because wanted is missing' => '',
   'Use existing templates'      => '',
   'Use for Factur-X/ZUGFeRD'    => '',
+  'Use for Swiss QR-Bill'       => '',
   'Use master default bin for Default Transfer, if no default bin for the part is configured' => '',
   'Use settings from client configuration' => '',
   'Use text field for department of contacts' => '',
@@ -4083,10 +4229,18 @@ $self->{texts} = {
   'Version'                     => '',
   'Version actions'             => '',
   'Version number'              => '',
-  'Version: '                   => '',
   'Versions'                    => '',
+  'View RFQs'                   => '',
   'View SEPA export'            => '',
   'View background job execution result' => '',
+  'View purchase delivery orders' => '',
+  'View purchase invoices'      => '',
+  'View purchase orders'        => '',
+  'View record links from Sales Order' => '',
+  'View sales delivery orders'  => '',
+  'View sales invoices and credit notes' => '',
+  'View sales orders'           => '',
+  'View sales quotations'       => '',
   'View sent email'             => '',
   'View warehouse content'      => '',
   'View/edit all employees purchase documents' => '',
@@ -4106,6 +4260,7 @@ $self->{texts} = {
   'Warehouses'                  => '',
   'Warn before saving orders with duplicate parts (new controller only)' => '',
   'Warn before saving orders without a delivery date' => '',
+  'Warn before saving sales orders with missing customer order number (new controller only)' => '',
   'Warning'                     => '',
   'Warning! Loading a draft will discard unsaved data!' => '',
   'Warning: Faulty position ignored' => '',
@@ -4132,6 +4287,7 @@ $self->{texts} = {
   'What this template contains' => '',
   'What type of item is this?'  => '',
   'When converting a requirement spec into a quotation or an oder each section gets converted into a line position in the new record. This is the article used by default for this conversion.' => '',
+  'Whether or not to replace variable placeholders such as "<%invdate%>" in texts in positions such as the part description by the record\'s actual value' => '',
   'Which is located at doc/kivitendo-Dokumentation.pdf. Click here: ' => '',
   'With Attachments'            => '',
   'With Extension Of Time'      => '',
@@ -4292,7 +4448,6 @@ $self->{texts} = {
   'delivered'                   => '',
   'deliverydate'                => '',
   'difference as skonto'        => '',
-  'difference_as_skonto'        => '',
   'direct debit'                => '',
   'disposed'                    => '',
   'disposed_br'                 => 'disposed',
@@ -4321,6 +4476,7 @@ $self->{texts} = {
   'filename'                    => '',
   'filename has not uploadable characters ' => '',
   'filesize too big: '          => '',
+  'final_invoice'               => '',
   'flat-rate position'          => '',
   'follow_up_list'              => '',
   'for'                         => '',
@@ -4347,6 +4503,7 @@ $self->{texts} = {
   'internal error (see details)' => '',
   'invoice'                     => '',
   'invoice mode or item mode'   => '',
+  'invoice_for_advance_payment' => '',
   'invoice_list'                => '',
   'is'                          => '',
   'is after'                    => '',
@@ -4451,6 +4608,7 @@ $self->{texts} = {
   'return_material'             => '',
   'revert deleted'              => '',
   'rfq_list'                    => '',
+  'rma_delivery_order_list'     => '',
   'running'                     => '',
   'sales tax identification number' => '',
   'sales_delivery_order_list'   => '',
@@ -4480,6 +4638,7 @@ $self->{texts} = {
   'stocktaking'                 => '',
   'succeeded'                   => '',
   'sum'                         => '',
+  'supplier_delivery_order_list' => '',
   'tax_chartaccno'              => '',
   'tax_percent'                 => '',
   'tax_rate'                    => '',
@@ -4522,6 +4681,8 @@ $self->{texts} = {
   'warehouse_journal_list'      => '',
   'warehouse_report_list'       => '',
   'warehouse_usage_list'        => '',
+  'will be set upon posting'    => '',
+  'will be set upon saving'     => '',
   'with skonto acc. to pt'      => '',
   'with_skonto_pt'              => '',
   'without skonto'              => '',
index 8437374..104dd4d 100644 (file)
@@ -29,11 +29,13 @@ order=< > \n
 \n=<br>
 
 [Template/LaTeX]
-order=\\ <pagebreak> & \n \r " $ <bullet> % _ # ^ { } < > £ ± ² ³ ° § ® © ~ \xad \xa0 ➔ → ← | − ≤ ≥ ‐ ​ Ω μ Δ λ Ø ø ‑
+order=\\ <pagebreak> & \n \r " $ <bullet> % _ # ^ { } < > £ ± ² ³ ° § ® © ~ \xad \xa0 ➔ → ← ↔ ↕ | − ≤ ≥ ‐ <200b> Ω μ Δ λ Ø ø ‑
 \\=\\textbackslash\s
 <pagebreak>=
-"=''
 &=\\&
+\n=\\newline\s
+\r=
+"=''
 $=\\$
 <bullet>=$\\bullet$
 %=\\%
@@ -41,39 +43,39 @@ _=\\_
 # A hash mark starts a comment; therefore the line is ignored. So use
 # its hex code instead.
 \x23=\\#
+^=\\^\\\s
 {=\\{
 }=\\}
 <=$<$
 >=$>$
 £=\\pounds\s
-\n=\\newline\s
-\r=
 ±=$\\pm$
-^=\\^\\\s
 ²=$^2$
 ³=$^3$
 °=$^\\circ$
-§=\\S\s
-®={\\textregistered}
-©={\\textcopyright}
+§=\\S
+®=\\textregistered
+©=\\textcopyright
+~={\\raisebox{0.5ex}{\\texttildelow}}
 \xad=\\-
+\xa0=~
 ➔=$\\rightarrow$
 →=$\\rightarrow$
 ←=$\\leftarrow$
-\xa0=~
+↔=$\\leftrightarrow$
+↕=$\\updownarrow$
 |={\\textbar}
 −={\\textemdash}
 ≤=$\\leq$
 ≥=$\\geq$
 ‐={}-{}
 ​={\\hspace{0pt}}
+Ω=$\\Omega$
 μ={\\textmu}
 Δ=$\\Delta$
-Ω=$\\Omega$
-~={\\raisebox{0.5ex}{\\texttildelow}}
 λ=$\\lambda$
-ø={\\o}
 Ø={\\O}
+ø={\\o}
 ‑={}-{}
 
 [Template/OpenDocument]
index a22a5a6..2a8777d 100644 (file)
   name: Quotations
   icon: report_quotations
   order: 200
-  access: sales_quotation_edit
+  access: sales_quotation_edit | sales_quotation_view
   module: oe.pl
   params:
     action: search
   name: Sales Orders
   icon: report_sales_orders
   order: 300
-  access: sales_order_edit
+  access: sales_order_edit | sales_order_view
   module: oe.pl
   params:
     action: search
   name: Delivery Orders
   icon: delivery_order_report
   order: 400
-  access: sales_delivery_order_edit
+  access: sales_delivery_order_edit | sales_delivery_order_view
   module: do.pl
   params:
     action: search
   name: RFQs
   icon: rfq_report
   order: 100
-  access: request_quotation_edit
+  access: request_quotation_edit | request_quotation_view
   module: oe.pl
   params:
     action: search
   name: Purchase Orders
   icon: purchase_order_report
   order: 200
-  access: purchase_order_edit
+  access: purchase_order_edit | purchase_order_view
   module: oe.pl
   params:
     action: search
   id: ap_reports_delivery_orders
   name: Delivery Orders
   order: 300
-  access: purchase_delivery_order_edit
+  access: purchase_delivery_order_edit | purchase_delivery_order_view
   module: do.pl
   params:
     action: search
     type: purchase_delivery_order
+- parent: ap_reports
+  id: ap_reports_supplier_delivery_orders
+  name: Supplier Delivery Orders
+  order: 350
+  access: purchase_delivery_order_edit | purchase_delivery_order_view
+  module: do.pl
+  params:
+    action: search
+    type: supplier_delivery_order
 - parent: ap_reports
   id: ap_reports_vendor_invoices_ap_transactions
   name: Vendor Invoices & AP Transactions
   params:
     action: CsvImport/new
     profile.type: contacts
+- parent: system_import_csv
+  id: system_import_csv_additional_billing_address
+  name: Additional Billing Addresses
+  order: 250
+  params:
+    action: CsvImport/new
+    profile.type: billing_addresses
 - parent: system_import_csv
   id: system_import_csv_shipto
   name: Shipto
diff --git a/menus/user/20-invoice-for-advance-payment.yaml b/menus/user/20-invoice-for-advance-payment.yaml
new file mode 100644 (file)
index 0000000..b76dcad
--- /dev/null
@@ -0,0 +1,10 @@
+- parent: ar
+  id: ar_add_sales_invoice_for_advance_payment
+  name: Add Invoice for Advance Payment
+  icon: sales_invoice_add
+  order: 550
+  access: invoice_edit
+  module: is.pl
+  params:
+    action: add
+    type: invoice_for_advance_payment
index 8bbe93d..bf4ffaa 100755 (executable)
@@ -2,6 +2,8 @@
 
 use warnings;
 use strict;
+use utf8;
+use open qw(:std :utf8);
 use 5.008;                          # too much magic in here to include perl 5.6
 
 BEGIN {
@@ -64,6 +66,10 @@ sub execute_code {
 my $repl = Devel::REPL->new;
 $repl->load_plugin($_) for @plugins;
 $repl->load_history($history_file);
+
+binmode($repl->out_fh, 'utf8');
+
+$repl->eval('use utf8;');
 $repl->eval('help');
 $repl->print("trying to auto login into client '$client' with login '$login'...\n");
 execute_code($repl, "lxinit '$client', '$login'");
diff --git a/sql/Pg-upgrade2-auth/convert_columns_to_html_for_sending_html_emails.pl b/sql/Pg-upgrade2-auth/convert_columns_to_html_for_sending_html_emails.pl
new file mode 100644 (file)
index 0000000..f8ffbe6
--- /dev/null
@@ -0,0 +1,46 @@
+# @tag: convert_columns_to_html_for_sending_html_emails
+# @description: Versand von E-Mails in HTML: mehrere Text-Spalten nach HTML umwandeln
+# @depends: release_3_5_8
+package SL::DBUpgrade2::Auth::convert_columns_to_html_for_sending_html_emails;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+use SL::HTML::Util;
+
+sub run {
+  my ($self) = @_;
+
+  my $q_fetch = <<SQL;
+    SELECT user_id, cfg_key, cfg_value
+    FROM auth.user_config
+    WHERE (cfg_key = 'signature')
+SQL
+
+  my $q_update = <<SQL;
+    UPDATE auth.user_config
+    SET cfg_value = ?
+    WHERE (user_id = ?)
+      AND (cfg_key = 'signature')
+SQL
+
+  my $h_fetch = $self->dbh->prepare($q_fetch);
+  $h_fetch->execute || $::form->dberror($q_fetch);
+
+  my $h_update = $self->dbh->prepare($q_update);
+
+  while (my $entry = $h_fetch->fetchrow_hashref) {
+    $entry->{cfg_value} //= '';
+    my $new_value = SL::HTML::Util->plain_text_to_html($entry->{cfg_value});
+
+    next if $entry->{cfg_value} eq $new_value;
+
+    $h_update->execute($new_value, $entry->{user_id}) || $::form->dberror($q_update);
+  }
+
+  return 1;
+}
+
+1;
diff --git a/sql/Pg-upgrade2-auth/release_3_6_0.sql b/sql/Pg-upgrade2-auth/release_3_6_0.sql
new file mode 100644 (file)
index 0000000..a7142ef
--- /dev/null
@@ -0,0 +1,3 @@
+-- @tag: release_3_6_0
+-- @description: Abhängigkeitsscript für Release 3.6.0
+-- @depends: release_3_5_8 convert_columns_to_html_for_sending_html_emails
diff --git a/sql/Pg-upgrade2-auth/release_3_6_1.sql b/sql/Pg-upgrade2-auth/release_3_6_1.sql
new file mode 100644 (file)
index 0000000..6a9f3f3
--- /dev/null
@@ -0,0 +1,3 @@
+-- @tag: release_3_6_1
+-- @description: Abhängigkeitsscript für Release 3.6.1
+-- @depends: release_3_6_0 rights_view_docs
diff --git a/sql/Pg-upgrade2-auth/rights_view_docs.sql b/sql/Pg-upgrade2-auth/rights_view_docs.sql
new file mode 100644 (file)
index 0000000..2591ada
--- /dev/null
@@ -0,0 +1,80 @@
+-- @tag: rights_view_docs
+-- @description: Rechte zum Lesen von Belegen
+-- @depends: release_3_6_0
+-- @locales: View sales quotations
+-- @locales: View sales orders
+-- @locales: View sales delivery orders
+-- @locales: View sales invoices and credit notes
+-- @locales: View RFQs
+-- @locales: View purchase orders
+-- @locales: View purchase delivery orders
+-- @locales: View purchase invoices
+
+INSERT INTO auth.master_rights (position, name, description, category)
+  VALUES ((SELECT position + 10 FROM auth.master_rights WHERE name = 'sales_quotation_edit'),
+          'sales_quotation_view',
+           'View sales quotations',
+          FALSE);
+
+INSERT INTO auth.master_rights (position, name, description, category)
+  VALUES ((SELECT position + 10 FROM auth.master_rights WHERE name = 'sales_order_edit'),
+          'sales_order_view',
+           'View sales orders',
+          FALSE);
+
+INSERT INTO auth.master_rights (position, name, description, category)
+  VALUES ((SELECT position + 10 FROM auth.master_rights WHERE name = 'sales_delivery_order_edit'),
+          'sales_delivery_order_view',
+           'View sales delivery orders',
+          FALSE);
+
+INSERT INTO auth.master_rights (position, name, description, category)
+  VALUES ((SELECT position + 10 FROM auth.master_rights WHERE name = 'invoice_edit'),
+          'sales_invoice_view',
+          'View sales invoices and credit notes',
+          FALSE);
+
+INSERT INTO auth.master_rights (position, name, description, category)
+  VALUES ((SELECT position + 10 FROM auth.master_rights WHERE name = 'request_quotation_edit'),
+          'request_quotation_view',
+           'View RFQs',
+          FALSE);
+
+INSERT INTO auth.master_rights (position, name, description, category)
+  VALUES ((SELECT position + 10 FROM auth.master_rights WHERE name = 'purchase_order_edit'),
+          'purchase_order_view',
+           'View purchase orders',
+          FALSE);
+
+INSERT INTO auth.master_rights (position, name, description, category)
+  VALUES ((SELECT position + 10 FROM auth.master_rights WHERE name = 'purchase_delivery_order_edit'),
+          'purchase_delivery_order_view',
+           'View purchase delivery orders',
+          FALSE);
+
+INSERT INTO auth.master_rights (position, name, description, category)
+  VALUES ((SELECT position + 10 FROM auth.master_rights WHERE name = 'vendor_invoice_edit'),
+          'purchase_invoice_view',
+          'View purchase invoices',
+          FALSE);
+
+
+-- INSERT INTO auth.group_rights (group_id, "right", granted)
+--    SELECT (SELECT id FROM auth.group WHERE name = 'Vollzugriff'), 'sales_quotation_view',         true UNION
+--    SELECT (SELECT id FROM auth.group WHERE name = 'Vollzugriff'), 'sales_order_view',             true UNION
+--    SELECT (SELECT id FROM auth.group WHERE name = 'Vollzugriff'), 'sales_delivery_order_view',    true UNION
+--    SELECT (SELECT id FROM auth.group WHERE name = 'Vollzugriff'), 'sales_invoice_view',           true UNION
+--    SELECT (SELECT id FROM auth.group WHERE name = 'Vollzugriff'), 'request_quotation_view',       true UNION
+--    SELECT (SELECT id FROM auth.group WHERE name = 'Vollzugriff'), 'purchase_order_view',          true UNION
+--    SELECT (SELECT id FROM auth.group WHERE name = 'Vollzugriff'), 'purchase_delivery_order_view', true UNION
+--    SELECT (SELECT id FROM auth.group WHERE name = 'Vollzugriff'), 'purchase_invoice_view',        true;
+
+INSERT INTO auth.group_rights (group_id, "right", granted)
+   SELECT id, 'sales_quotation_view',         true FROM auth.group WHERE name = 'Vollzugriff' UNION
+   SELECT id, 'sales_order_view',             true FROM auth.group WHERE name = 'Vollzugriff' UNION
+   SELECT id, 'sales_delivery_order_view',    true FROM auth.group WHERE name = 'Vollzugriff' UNION
+   SELECT id, 'sales_invoice_view',           true FROM auth.group WHERE name = 'Vollzugriff' UNION
+   SELECT id, 'request_quotation_view',       true FROM auth.group WHERE name = 'Vollzugriff' UNION
+   SELECT id, 'purchase_order_view',          true FROM auth.group WHERE name = 'Vollzugriff' UNION
+   SELECT id, 'purchase_delivery_order_view', true FROM auth.group WHERE name = 'Vollzugriff' UNION
+   SELECT id, 'purchase_invoice_view',        true FROM auth.group WHERE name = 'Vollzugriff';
diff --git a/sql/Pg-upgrade2/add_gl_transaction_description.sql b/sql/Pg-upgrade2/add_gl_transaction_description.sql
new file mode 100644 (file)
index 0000000..a8c7b13
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: add_gl_transaction_description
+-- @description: Vorgangsbezeichnung für Dialogbuchungen
+-- @depends: release_3_5_8
+
+ALTER TABLE gl ADD transaction_description TEXT;
diff --git a/sql/Pg-upgrade2/add_record_templates_transaction_description.sql b/sql/Pg-upgrade2/add_record_templates_transaction_description.sql
new file mode 100644 (file)
index 0000000..e54fc98
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: add_record_templates_transaction_description
+-- @description: Vorgangsbezeichnung in Dialog-Vorlage ergänzen
+-- @depends: release_3_5_8 create_record_template_tables
+
+ALTER TABLE record_templates ADD COLUMN transaction_description TEXT;
diff --git a/sql/Pg-upgrade2/ap_gl.sql b/sql/Pg-upgrade2/ap_gl.sql
new file mode 100644 (file)
index 0000000..cb9e01b
--- /dev/null
@@ -0,0 +1,16 @@
+-- @tag: ap_gl
+-- @description: Hilfstabelle für automatische GL-Buchung nach Kreditorenbuchung
+-- @depends: release_3_5_0
+-- @ignore: 0
+      CREATE TABLE ap_gl (
+        ap_id                   integer,
+        gl_id                   integer,
+        itime                   TIMESTAMP      DEFAULT now(),
+        mtime                   TIMESTAMP,
+        PRIMARY KEY (ap_id, gl_id),
+        FOREIGN KEY (ap_id)                    REFERENCES ap (id),
+        FOREIGN KEY (gl_id)                    REFERENCES gl (id) ON DELETE CASCADE);
+
+
+
+
diff --git a/sql/Pg-upgrade2/ar_add_qrbill_without_amount.sql b/sql/Pg-upgrade2/ar_add_qrbill_without_amount.sql
new file mode 100644 (file)
index 0000000..15a1602
--- /dev/null
@@ -0,0 +1,6 @@
+-- @tag: ar_add_qrbill_without_amount
+-- @description: Spalte für QR-Rechnung ohne Betrag
+-- @depends: release_3_5_8
+ALTER TABLE ar ADD COLUMN qrbill_without_amount boolean;
+ALTER TABLE ar ALTER COLUMN qrbill_without_amount SET DEFAULT FALSE;
+UPDATE ar SET qrbill_without_amount = FALSE;
diff --git a/sql/Pg-upgrade2/bank_account_informations_for_swiss_qrbill.sql b/sql/Pg-upgrade2/bank_account_informations_for_swiss_qrbill.sql
new file mode 100644 (file)
index 0000000..0c8c64c
--- /dev/null
@@ -0,0 +1,14 @@
+-- @tag: bank_account_information_for_swiss_qrbill
+-- @description: Bankkonto Informationen für Swiss QR-Bill hinzufügen
+-- @depends: release_3_5_6_1
+ALTER TABLE bank_accounts ADD COLUMN use_for_qrbill BOOLEAN;
+ALTER TABLE bank_accounts ADD COLUMN bank_account_id VARCHAR;
+
+UPDATE bank_accounts SET use_for_qrbill = (
+    SELECT COUNT(*)
+    FROM bank_accounts
+  ) = 1;
+
+ALTER TABLE bank_accounts
+  ALTER COLUMN use_for_qrbill SET DEFAULT FALSE,
+  ALTER COLUMN use_for_qrbill SET NOT NULL;
diff --git a/sql/Pg-upgrade2/clean_tax_18_19.pl b/sql/Pg-upgrade2/clean_tax_18_19.pl
new file mode 100644 (file)
index 0000000..423fa7a
--- /dev/null
@@ -0,0 +1,74 @@
+# @tag: clean_tax_18_19
+# @description: Vorbereitung für neue Steuerschlüssel 18,19
+# @depends: release_3_6_0 tax_reverse_charge
+# @ignore: 0
+package SL::DBUpgrade2::clean_tax_18_19;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+sub delete_alter_tax {
+  my $self = shift;
+
+  my $query = <<SQL;
+    SELECT id from tax
+    where taxkey = ?
+    and reverse_charge_chart_id is null
+SQL
+  my $q_fetch = <<SQL;
+    SELECT trans_id
+    FROM acc_trans where tax_id = ?
+    LIMIT 1
+SQL
+
+  my $delete_taxkey = <<SQL;
+    DELETE from taxkeys where tax_id = ?
+SQL
+
+  my $delete_tax = <<SQL;
+    DELETE from tax where         id = ?
+SQL
+
+
+  my $edit_tax = <<SQL;
+    UPDATE tax set chart_id = NULL
+    WHERE id = ?
+SQL
+
+
+  my $h_fetch   = $self->dbh->prepare($query);
+  my $acc_fetch = $self->dbh->prepare($q_fetch);
+  my $delete_tk = $self->dbh->prepare($delete_taxkey);
+  my $delete_t  = $self->dbh->prepare($delete_tax);
+  my $edit_q    = $self->dbh->prepare($edit_tax);
+
+
+  my $tax_id;
+  foreach ( qw(18 19) ) {
+    $h_fetch->execute($_) || $::form->dberror($query);
+    while (my $entry = $h_fetch->fetchrow_hashref) {
+      $tax_id = $entry->{id};
+      next unless $tax_id;
+      $edit_q->execute($tax_id)    || $::form->dberror($edit_tax);
+      $acc_fetch->execute($tax_id) || $::form->dberror($q_fetch);
+      if (!$acc_fetch->fetchrow_hashref) {
+        $delete_tk->execute($tax_id) || $::form->dberror($delete_tk);
+        $delete_t ->execute($tax_id) || $::form->dberror($delete_t);
+      }
+    }
+  }
+}
+
+sub run {
+  my ($self) = @_;
+
+  return 1 unless ($self->check_coa('Germany-DATEV-SKR03EU') ||$self->check_coa('Germany-DATEV-SKR04EU'));
+
+  $self->delete_alter_tax;
+
+  return 1;
+}
+
+1;
diff --git a/sql/Pg-upgrade2/convert_columns_to_html_for_sending_html_emails.pl b/sql/Pg-upgrade2/convert_columns_to_html_for_sending_html_emails.pl
new file mode 100644 (file)
index 0000000..168ea45
--- /dev/null
@@ -0,0 +1,62 @@
+# @tag: convert_columns_to_html_for_sending_html_emails
+# @description: Versand von E-Mails in HTML: mehrere Text-Spalten nach HTML umwandeln
+# @depends: release_3_5_8
+package SL::DBUpgrade2::convert_columns_to_html_for_sending_html_emails;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+use SL::HTML::Util;
+
+sub convert_column {
+  my ($self, $table, $id_column, $column_to_convert, $condition) = @_;
+
+  $condition = $condition ? "WHERE $condition" : "";
+
+  my $q_fetch = <<SQL;
+    SELECT ${id_column}, ${column_to_convert}
+    FROM ${table}
+    ${condition}
+SQL
+
+  my $q_update = <<SQL;
+    UPDATE ${table}
+    SET ${column_to_convert} = ?
+    WHERE ${id_column} = ?
+SQL
+
+  my $h_fetch = $self->dbh->prepare($q_fetch);
+  $h_fetch->execute || $::form->dberror($q_fetch);
+
+  my $h_update = $self->dbh->prepare($q_update);
+
+  while (my $entry = $h_fetch->fetchrow_hashref) {
+    $entry->{$column_to_convert} //= '';
+    my $new_value = SL::HTML::Util->plain_text_to_html($entry->{$column_to_convert});
+
+    next if $entry->{$column_to_convert} eq $new_value;
+
+    $h_update->execute($new_value, $entry->{id}) || $::form->dberror($q_update);
+  }
+}
+
+sub run {
+  my ($self) = @_;
+
+  $self->convert_column('defaults',                  'id', 'signature');
+  $self->convert_column('employee',                  'id', 'deleted_signature');
+  $self->convert_column('periodic_invoices_configs', 'id', 'email_body');
+  $self->convert_column('generic_translations',      'id', 'translation', <<SQL);
+    translation_type IN (
+      'preset_text_sales_quotation', 'preset_text_sales_order', 'preset_text_sales_delivery_order',
+      'preset_text_invoice', 'preset_text_invoice_direct_debit', 'preset_text_request_quotation',
+      'preset_text_purchase_order', 'preset_text_periodic_invoices_email_body'
+    )
+SQL
+
+  return 1;
+}
+
+1;
diff --git a/sql/Pg-upgrade2/convert_columns_to_html_for_sending_html_emails2.pl b/sql/Pg-upgrade2/convert_columns_to_html_for_sending_html_emails2.pl
new file mode 100644 (file)
index 0000000..9c79104
--- /dev/null
@@ -0,0 +1,53 @@
+# @tag: convert_columns_to_html_for_sending_html_emails2
+# @description: Versand von E-Mails in HTML: weitere Text-Spalten nach HTML umwandeln
+# @depends: convert_columns_to_html_for_sending_html_emails
+package SL::DBUpgrade2::convert_columns_to_html_for_sending_html_emails2;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+use SL::HTML::Util;
+
+sub convert_column {
+  my ($self, $table, $id_column, $column_to_convert, $condition) = @_;
+
+  $condition = $condition ? "WHERE $condition" : "";
+
+  my $q_fetch = <<SQL;
+    SELECT ${id_column}, ${column_to_convert}
+    FROM ${table}
+    ${condition}
+SQL
+
+  my $q_update = <<SQL;
+    UPDATE ${table}
+    SET ${column_to_convert} = ?
+    WHERE ${id_column} = ?
+SQL
+
+  my $h_fetch = $self->dbh->prepare($q_fetch);
+  $h_fetch->execute || $::form->dberror($q_fetch);
+
+  my $h_update = $self->dbh->prepare($q_update);
+
+  while (my $entry = $h_fetch->fetchrow_hashref) {
+    $entry->{$column_to_convert} //= '';
+    my $new_value = SL::HTML::Util->plain_text_to_html($entry->{$column_to_convert});
+
+    next if $entry->{$column_to_convert} eq $new_value;
+
+    $h_update->execute($new_value, $entry->{id}) || $::form->dberror($q_update);
+  }
+}
+
+sub run {
+  my ($self) = @_;
+
+  $self->convert_column('dunning_config', 'id', 'email_body');
+
+  return 1;
+}
+
+1;
diff --git a/sql/Pg-upgrade2/convert_real_qty.sql b/sql/Pg-upgrade2/convert_real_qty.sql
new file mode 100644 (file)
index 0000000..5e0ea65
--- /dev/null
@@ -0,0 +1,7 @@
+-- @tag: convert_real_qty
+-- @description: Spaltentyp auf Numeric anstelle von Real für qty
+-- @depends: release_3_6_0
+ALTER TABLE orderitems ALTER column qty type numeric(25,5);
+ALTER TABLE invoice    ALTER column qty type numeric(25,5);
+
+
diff --git a/sql/Pg-upgrade2/custom_variables_convert_width_height_to_pixels.pl b/sql/Pg-upgrade2/custom_variables_convert_width_height_to_pixels.pl
new file mode 100644 (file)
index 0000000..45b22f8
--- /dev/null
@@ -0,0 +1,59 @@
+# @tag: custom_variables_convert_width_height_to_pixels
+# @description: Benutzerdefinierte Variablen: Optionen »WIDTH« & »HEIGHT« nach Pixel konvertieren
+# @depends: release_3_5_8
+package SL::DBUpgrade2::custom_variables_convert_width_height_to_pixels;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+use SL::DBUtils;
+
+sub find_configs {
+  my ($self) = @_;
+
+  my $sql = <<SQL;
+    SELECT id, options
+    FROM custom_variable_configs
+    WHERE (COALESCE(options, '') ~ 'WIDTH=|HEIGHT=')
+      AND (type = 'textfield')
+SQL
+
+  return selectall_hashref_query($::form, $self->dbh, $sql);
+}
+
+sub fix_configs {
+  my ($self, $configs) = @_;
+
+  my $sql = <<SQL;
+    UPDATE custom_variable_configs
+    SET options = ?
+    WHERE id = ?
+SQL
+
+  my $update_h = prepare_query($::form, $self->dbh, $sql);
+
+  # Old defaults: 30 columns, 5 rows
+  # New defaults: 225px width, 90px height
+
+  foreach my $config (@{ $configs }) {
+    $config->{options} =~ s{WIDTH=(\d+)}{  int($1 * (225 / 30.0)) }eg;
+    $config->{options} =~ s{HEIGHT=(\d+)}{ int($1 * ( 90 /  5.0)) }eg;
+
+    $update_h->execute(@{$config}{qw(options id)}) || $self->db_error($sql);
+  }
+
+  $update_h->finish;
+}
+
+sub run {
+  my ($self) = @_;
+
+  my $configs = $self->find_configs;
+  $self->fix_configs($configs) if @{ $configs };
+
+  return 1;
+}
+
+1;
diff --git a/sql/Pg-upgrade2/customer_additional_billing_addresses.sql b/sql/Pg-upgrade2/customer_additional_billing_addresses.sql
new file mode 100644 (file)
index 0000000..11fcfb0
--- /dev/null
@@ -0,0 +1,45 @@
+-- @tag: customer_additional_billing_addresses
+-- @description: Kundenstammdaten: zusätzliche Rechnungsadressen
+-- @depends: release_3_5_8
+CREATE TABLE additional_billing_addresses (
+  id              SERIAL,
+  customer_id     INTEGER,
+  name            TEXT,
+  department_1    TEXT,
+  department_2    TEXT,
+  contact         TEXT,
+  street          TEXT,
+  zipcode         TEXT,
+  city            TEXT,
+  country         TEXT,
+  gln             TEXT,
+  email           TEXT,
+  phone           TEXT,
+  fax             TEXT,
+  default_address BOOLEAN NOT NULL DEFAULT FALSE,
+
+  itime           TIMESTAMP NOT NULL DEFAULT now(),
+  mtime           TIMESTAMP NOT NULL DEFAULT now(),
+
+  PRIMARY KEY (id),
+  FOREIGN KEY (customer_id) REFERENCES customer (id)
+);
+
+CREATE TRIGGER mtime_additional_billing_addresses
+BEFORE UPDATE ON additional_billing_addresses
+FOR EACH ROW EXECUTE PROCEDURE set_mtime();
+
+ALTER TABLE oe
+  ADD COLUMN billing_address_id INTEGER,
+  ADD FOREIGN KEY (billing_address_id)
+    REFERENCES additional_billing_addresses (id);
+
+ALTER TABLE delivery_orders
+  ADD COLUMN billing_address_id INTEGER,
+  ADD FOREIGN KEY (billing_address_id)
+    REFERENCES additional_billing_addresses (id);
+
+ALTER TABLE ar
+  ADD COLUMN billing_address_id INTEGER,
+  ADD FOREIGN KEY (billing_address_id)
+    REFERENCES additional_billing_addresses (id);
diff --git a/sql/Pg-upgrade2/customer_remove_empty_additional_billing_addresses.sql b/sql/Pg-upgrade2/customer_remove_empty_additional_billing_addresses.sql
new file mode 100644 (file)
index 0000000..bb60358
--- /dev/null
@@ -0,0 +1,16 @@
+-- @tag: customer_remove_empty_additional_billing_addresses
+-- @description: Leere »zusätzliche Rechnungsadressen« entfernen
+-- @depends: customer_additional_billing_addresses
+DELETE
+FROM additional_billing_addresses
+WHERE (coalesce(name,         '') = '')
+  AND (coalesce(department_1, '') = '')
+  AND (coalesce(department_2, '') = '')
+  AND (coalesce(contact,      '') = '')
+  AND (coalesce(street,       '') = '')
+  AND (coalesce(zipcode,      '') = '')
+  AND (coalesce(city,         '') = '')
+  AND (coalesce(country,      '') = '')
+  AND (coalesce(email,        '') = '')
+  AND (coalesce(phone,        '') = '')
+  AND (coalesce(fax,          '') = '');
diff --git a/sql/Pg-upgrade2/defaults_advance_payment_clearing_chart_id.sql b/sql/Pg-upgrade2/defaults_advance_payment_clearing_chart_id.sql
new file mode 100644 (file)
index 0000000..53da908
--- /dev/null
@@ -0,0 +1,32 @@
+-- @tag: defaults_advance_payment_clearing_chart_id
+-- @description: Voreingestelltes Konto für Verrechnung von Anzahlungen
+-- @depends: new_chart_1593_1495
+
+ALTER TABLE defaults ADD COLUMN advance_payment_clearing_chart_id INTEGER;
+
+DO $$
+BEGIN
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+    DECLARE
+      clearing_accno text := '1593';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+        UPDATE defaults SET advance_payment_clearing_chart_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+      END IF;
+    END;
+  END IF;
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+    DECLARE
+      clearing_accno text := '1495';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+        UPDATE defaults SET advance_payment_clearing_chart_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+      END IF;
+    END;
+  END IF;
+
+END $$;
diff --git a/sql/Pg-upgrade2/defaults_advance_payment_transfer_charts.sql b/sql/Pg-upgrade2/defaults_advance_payment_transfer_charts.sql
new file mode 100644 (file)
index 0000000..f77b257
--- /dev/null
@@ -0,0 +1,59 @@
+-- @tag: defaults_advance_payment_transfer_charts
+-- @description: Standardkonten für erhaltene versteuerte Anzahlungen 7% und 19% setzen
+-- @depends:new_chart_3260_1711 new_chart_3272_1718 defaults_advance_payment_clearing_chart_id
+
+
+ALTER TABLE defaults ADD COLUMN advance_payment_taxable_19_id INTEGER;
+ALTER TABLE defaults ADD COLUMN advance_payment_taxable_7_id  INTEGER;
+UPDATE chart set link ='AR' where id = (select advance_payment_clearing_chart_id from defaults);
+
+
+DO $$
+BEGIN
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+    DECLARE
+      clearing_accno text := '1718';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+        UPDATE defaults SET advance_payment_taxable_19_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+      END IF;
+    END;
+  END IF;
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+    DECLARE
+      clearing_accno text := '3272';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+        UPDATE defaults SET advance_payment_taxable_19_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+      END IF;
+    END;
+  END IF;
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+    DECLARE
+      clearing_accno text := '1711';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+        UPDATE defaults SET advance_payment_taxable_7_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+      END IF;
+    END;
+  END IF;
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+    DECLARE
+      clearing_accno text := '3260';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE clearing_accno ) = 1 THEN
+        UPDATE defaults SET advance_payment_taxable_7_id = (SELECT id FROM chart WHERE accno LIKE clearing_accno);
+      END IF;
+    END;
+  END IF;
+
+
+END $$;
diff --git a/sql/Pg-upgrade2/defaults_create_qrbill_data.sql b/sql/Pg-upgrade2/defaults_create_qrbill_data.sql
new file mode 100644 (file)
index 0000000..cffde9b
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: defaults_create_qrbill_data
+-- @description: Swiss QR-Bill Informationserzeugung Einstellungsoption
+-- @depends: release_3_5_6_1
+ALTER TABLE defaults ADD COLUMN create_qrbill_invoices BOOLEAN;
+UPDATE defaults SET create_qrbill_invoices = FALSE;
diff --git a/sql/Pg-upgrade2/defaults_invoice_prevent_browser_back.sql b/sql/Pg-upgrade2/defaults_invoice_prevent_browser_back.sql
new file mode 100644 (file)
index 0000000..c12e82b
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: defaults_invoice_prevent_browser_back
+-- @description: Verhinderung Browser-Zurück-Knopf einstellbar in Mandantenkonfiguration
+-- @depends: release_3_6_0
+
+ALTER TABLE defaults ADD COLUMN invoice_prevent_browser_back boolean NOT NULL DEFAULT FALSE;
diff --git a/sql/Pg-upgrade2/defaults_invoice_warn_no_delivery_order.sql b/sql/Pg-upgrade2/defaults_invoice_warn_no_delivery_order.sql
new file mode 100644 (file)
index 0000000..0038cab
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: defaults_invoice_warn_no_delivery_order
+-- @description: Mandantenkonfiguration: Warnung bei fehlendem Lieferschein als Vorgänger zur Rechnung
+-- @depends: release_3_5_8
+
+ALTER TABLE defaults ADD COLUMN warn_no_delivery_order_for_invoice BOOLEAN DEFAULT FALSE;
diff --git a/sql/Pg-upgrade2/defaults_order_controller.sql b/sql/Pg-upgrade2/defaults_order_controller.sql
new file mode 100644 (file)
index 0000000..0051710
--- /dev/null
@@ -0,0 +1,4 @@
+-- @tag: defaults_order_controller
+-- @description: Mandantenkonfiguration: Order-Controller auf aktiv setzen
+-- @depends: release_3_5_8
+UPDATE defaults SET feature_experimental_order = TRUE;
diff --git a/sql/Pg-upgrade2/defaults_order_warn_no_cusordnumber.sql b/sql/Pg-upgrade2/defaults_order_warn_no_cusordnumber.sql
new file mode 100644 (file)
index 0000000..e101bb0
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: defaults_order_warn_no_cusordnumber
+-- @description: Mandantenkonfiguration: Warnung bei fehlender Kundenbestellnummer in Verkaufsaufträgen
+-- @depends: release_3_5_8
+
+ALTER TABLE defaults ADD COLUMN order_warn_no_cusordnumber BOOLEAN DEFAULT FALSE;
diff --git a/sql/Pg-upgrade2/defaults_partsgroup_required.sql b/sql/Pg-upgrade2/defaults_partsgroup_required.sql
new file mode 100644 (file)
index 0000000..5250002
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: defaults_partsgroup_required
+-- @description: New setting to check that partsgroup is set when saving parts
+-- @depends: release_3_5_8
+
+ALTER TABLE defaults ADD COLUMN partsgroup_required boolean NOT NULL DEFAULT false;
diff --git a/sql/Pg-upgrade2/defaults_print_interpolate_variables_in_positions.sql b/sql/Pg-upgrade2/defaults_print_interpolate_variables_in_positions.sql
new file mode 100644 (file)
index 0000000..04aa917
--- /dev/null
@@ -0,0 +1,6 @@
+-- @tag: defaults_print_interpolate_variables_in_positions
+-- @description: Drucken: Variablen in Belegpositionen interpolieren (abschaltbar via Mandantenkonfiguration)
+-- @depends: release_3_5_8
+ALTER TABLE defaults
+ADD COLUMN print_interpolate_variables_in_positions BOOLEAN
+DEFAULT TRUE NOT NULL;
diff --git a/sql/Pg-upgrade2/defaults_qrbill_variants.sql b/sql/Pg-upgrade2/defaults_qrbill_variants.sql
new file mode 100644 (file)
index 0000000..622e708
--- /dev/null
@@ -0,0 +1,6 @@
+-- @tag: defaults_qrbill_variants
+-- @description: Varianten für QR-Rechnung Auswahl
+-- @depends: defaults_create_qrbill_data
+ALTER TABLE defaults
+ALTER COLUMN create_qrbill_invoices TYPE INTEGER
+USING create_qrbill_invoices::INTEGER;
diff --git a/sql/Pg-upgrade2/defaults_sales_purchase_record_numbers_changeable.sql b/sql/Pg-upgrade2/defaults_sales_purchase_record_numbers_changeable.sql
new file mode 100644 (file)
index 0000000..d7dce55
--- /dev/null
@@ -0,0 +1,6 @@
+-- @tag: defaults_sales_purchase_record_numbers_changeable
+-- @description: Verkauf: Belegnummern nicht mehr ändern können
+-- @depends: release_3_5_8
+ALTER TABLE defaults
+ADD COLUMN sales_purchase_record_numbers_changeable BOOLEAN
+DEFAULT FALSE NOT NULL;
diff --git a/sql/Pg-upgrade2/defaults_view_record_links.sql b/sql/Pg-upgrade2/defaults_view_record_links.sql
new file mode 100644 (file)
index 0000000..fc142bb
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: defaults_view_record_links
+-- @description: Mandantenkonfiguration: Sichtweise für record links immer vom Auftrag
+-- @depends: release_3_5_8
+
+ALTER TABLE defaults ADD COLUMN always_record_links_from_order BOOLEAN DEFAULT FALSE;
diff --git a/sql/Pg-upgrade2/delete_wrong_charts_for_taxkeys.pl b/sql/Pg-upgrade2/delete_wrong_charts_for_taxkeys.pl
new file mode 100644 (file)
index 0000000..159d4b0
--- /dev/null
@@ -0,0 +1,62 @@
+# @tag: delete_wrong_charts_for_taxkeys
+# @description: Uralte falsch angelegte Automatikkonten raus -> Chance auf tax.chart_id unique setzen
+# @depends: release_3_6_0
+# @ignore: 0
+package SL::DBUpgrade2::delete_wrong_charts_for_taxkeys;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+sub delete_chart_id_tax {
+  my $self = shift;
+
+  my $q_fetch = <<SQL;
+    SELECT chart_id
+    FROM tax where chart_id is not null
+    GROUP BY chart_id HAVING COUNT(*) > 1
+SQL
+
+  # skr03
+  my $q_update = <<SQL;
+    UPDATE tax
+    SET chart_id = NULL
+    WHERE chart_id = ?
+    AND rate = 0.16
+    AND (taxkey = 19 OR taxkey = 13)
+    AND EXISTS (SELECT * FROM defaults WHERE coa = 'Germany-DATEV-SKR03EU')
+SQL
+
+  my $h_fetch = $self->dbh->prepare($q_fetch);
+  $h_fetch->execute || $::form->dberror($q_fetch);
+
+  my $h_update_03 = $self->dbh->prepare($q_update);
+
+  while (my $entry = $h_fetch->fetchrow_hashref) {
+    $h_update_03->execute($entry->{chart_id}) || $::form->dberror($q_update);
+  }
+  # might be unique now
+  $h_fetch->execute || $::form->dberror($q_fetch);
+
+  if (!$h_fetch->fetchrow_hashref) {
+    my $q_unique = <<SQL;
+      alter table tax
+      ADD CONSTRAINT chart_id_unique_tax UNIQUE (chart_id)
+SQL
+    my $q_unique_p = $self->dbh->prepare($q_unique);
+    $q_unique_p->execute || $::form->dberror($q_unique_p);
+  }
+}
+
+sub run {
+  my ($self) = @_;
+
+  return 1 unless $self->check_coa('Germany-DATEV-SKR03EU');
+
+  $self->delete_chart_id_tax;
+
+  return 1;
+}
+
+1;
diff --git a/sql/Pg-upgrade2/delete_wrong_charts_for_taxkeys_04.pl b/sql/Pg-upgrade2/delete_wrong_charts_for_taxkeys_04.pl
new file mode 100644 (file)
index 0000000..95e408f
--- /dev/null
@@ -0,0 +1,63 @@
+# @tag: delete_wrong_charts_for_taxkeys_04
+# @description: SKR04: Uralte falsch angelegte Automatikkonten raus -> Chance auf tax.chart_id unique setzen
+# @depends: release_3_6_0
+# @ignore: 0
+package SL::DBUpgrade2::delete_wrong_charts_for_taxkeys_04;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+sub delete_chart_id_tax {
+  my $self = shift;
+
+  my $q_fetch = <<SQL;
+    SELECT chart_id
+    FROM tax where chart_id is not null
+    GROUP BY chart_id HAVING COUNT(*) > 1
+SQL
+
+  # SKR04
+  my $q_update_04 = <<SQL;
+    UPDATE tax
+    SET chart_id = NULL
+    WHERE chart_id = ?
+    AND rate = 0.16
+    AND (taxkey = 3 OR taxkey = 9)
+    AND EXISTS (SELECT * FROM defaults WHERE coa = 'Germany-DATEV-SKR04EU')
+SQL
+
+
+  my $h_fetch = $self->dbh->prepare($q_fetch);
+  $h_fetch->execute || $::form->dberror($q_fetch);
+
+  my $h_update_04 = $self->dbh->prepare($q_update_04);
+
+  while (my $entry = $h_fetch->fetchrow_hashref) {
+    $h_update_04->execute($entry->{chart_id}) || $::form->dberror($q_update_04);
+  }
+  # might be unique now
+  $h_fetch->execute || $::form->dberror($q_fetch);
+
+  if (!$h_fetch->fetchrow_hashref) {
+    my $q_unique = <<SQL;
+      alter table tax
+      ADD CONSTRAINT chart_id_unique_tax UNIQUE (chart_id)
+SQL
+    my $q_unique_p = $self->dbh->prepare($q_unique);
+    $q_unique_p->execute || $::form->dberror($q_unique_p);
+  }
+}
+
+sub run {
+  my ($self) = @_;
+
+  return 1 unless $self->check_coa('Germany-DATEV-SKR04EU');
+
+  $self->delete_chart_id_tax;
+
+  return 1;
+}
+
+1;
diff --git a/sql/Pg-upgrade2/deliveryorder_transnumbers.sql b/sql/Pg-upgrade2/deliveryorder_transnumbers.sql
new file mode 100644 (file)
index 0000000..3e03150
--- /dev/null
@@ -0,0 +1,11 @@
+-- @tag: deliveryorder_transnumbers
+-- @description: Nummernkreise für neue lieferscheintypen
+-- @depends: release_3_5_8
+
+ALTER TABLE defaults ADD COLUMN sudonumber TEXT;
+ALTER TABLE defaults ADD COLUMN rdonumber TEXT;
+
+UPDATE defaults SET
+  sudonumber = '0',
+  rdonumber = '0';
+
diff --git a/sql/Pg-upgrade2/deliveryorder_type.sql b/sql/Pg-upgrade2/deliveryorder_type.sql
new file mode 100644 (file)
index 0000000..8e4a0f4
--- /dev/null
@@ -0,0 +1,12 @@
+-- @tag: deliveryorder_type
+-- @description: Persistente Typen in Lieferscheinen
+-- @depends: release_3_5_8
+
+ALTER TABLE delivery_orders ADD COLUMN order_type TEXT;
+
+UPDATE delivery_orders SET order_type = 'sales_delivery_order' WHERE customer_id IS NOT NULL;
+UPDATE delivery_orders SET order_type = 'purchase_delivery_order' WHERE vendor_id IS NOT NULL;
+
+ALTER TABLE delivery_orders ALTER COLUMN order_type SET NOT NULL;
+
+
diff --git a/sql/Pg-upgrade2/file_full_texts.sql b/sql/Pg-upgrade2/file_full_texts.sql
new file mode 100644 (file)
index 0000000..f479da1
--- /dev/null
@@ -0,0 +1,15 @@
+-- @tag: file_full_texts
+-- @description: Tabelle f. Volltext-Suche anlegen
+-- @depends: release_3_6_0
+
+CREATE TABLE IF NOT EXISTS file_full_texts (
+   id           SERIAL,
+   file_id      INTEGER            NOT NULL REFERENCES files(id) ON DELETE CASCADE,
+   full_text    TEXT               NOT NULL,
+   itime        TIMESTAMP          NOT NULL DEFAULT now(),
+   mtime        TIMESTAMP,
+
+   PRIMARY KEY (id)
+);
+
+CREATE TRIGGER mtime_file_full_texts BEFORE UPDATE ON file_full_texts FOR EACH ROW EXECUTE PROCEDURE set_mtime();
diff --git a/sql/Pg-upgrade2/file_storage_partial_invoices.sql b/sql/Pg-upgrade2/file_storage_partial_invoices.sql
new file mode 100644 (file)
index 0000000..7fed883
--- /dev/null
@@ -0,0 +1,18 @@
+-- @tag: file_storage_partial_invoices
+-- @description: Dateispeicher auch für Anzahlungs- und Schlussrechnung
+-- @depends: file_storage_project
+
+ALTER TABLE files
+  DROP CONSTRAINT valid_type;
+ALTER TABLE files
+  ADD  CONSTRAINT valid_type CHECK (
+             (object_type = 'credit_note'     ) OR (object_type = 'invoice'                 ) OR (object_type = 'sales_order'          )
+          OR (object_type = 'sales_quotation' ) OR (object_type = 'sales_delivery_order'    ) OR (object_type = 'request_quotation'    )
+          OR (object_type = 'purchase_order'  ) OR (object_type = 'purchase_delivery_order' ) OR (object_type = 'purchase_invoice'     )
+          OR (object_type = 'vendor'          ) OR (object_type = 'customer'                ) OR (object_type = 'part'                 )
+          OR (object_type = 'gl_transaction'  ) OR (object_type = 'dunning'                 ) OR (object_type = 'dunning1'             )
+          OR (object_type = 'dunning2'        ) OR (object_type = 'dunning3'                ) OR (object_type = 'dunning_orig_invoice' )
+          OR (object_type = 'dunning_invoice' ) OR (object_type = 'draft'                   ) OR (object_type = 'statement'            )
+          OR (object_type = 'shop_image'      ) OR (object_type = 'letter'                  ) OR (object_type = 'project'              )
+          OR (object_type = 'invoice_for_advance_payment') OR (object_type = 'final_invoice')
+  );
diff --git a/sql/Pg-upgrade2/files_add_variant.sql b/sql/Pg-upgrade2/files_add_variant.sql
new file mode 100644 (file)
index 0000000..a697e8a
--- /dev/null
@@ -0,0 +1,5 @@
+-- @tag: files_add_variant
+-- @description: Varianten für DMS System
+-- @depends: release_3_5_8
+
+ALTER TABLE files ADD COLUMN print_variant text;
diff --git a/sql/Pg-upgrade2/full_texts_background_job.sql b/sql/Pg-upgrade2/full_texts_background_job.sql
new file mode 100644 (file)
index 0000000..15a1ec9
--- /dev/null
@@ -0,0 +1,13 @@
+-- @tag: full_texts_background_job
+-- @description: Hintergrundjob für tägliche Extraktion von Texten aus Dokumenten
+-- @depends: release_3_6_0
+
+INSERT INTO background_jobs (type, package_name, active, cron_spec, next_run_at)
+VALUES ('interval', 'CreateOrUpdateFileFullTexts', true, '20 3 * * *',
+  CAST(current_date AS timestamp) + CAST(
+    (CASE
+     WHEN extract('hour' FROM current_timestamp) < 2 THEN '3 hours 20 minutes'
+     ELSE                                                 '1 day 3 hours 20 minutes'
+     END) AS interval
+  )
+);
diff --git a/sql/Pg-upgrade2/language_obsolete.sql b/sql/Pg-upgrade2/language_obsolete.sql
new file mode 100644 (file)
index 0000000..53d28b5
--- /dev/null
@@ -0,0 +1,6 @@
+-- @tag: language_obsolete
+-- @description: Sprachen ungültig setzen
+-- @depends: release_3_6_0
+-- @ignore: 0
+
+ALTER TABLE language ADD COLUMN obsolete BOOLEAN DEFAULT FALSE;
diff --git a/sql/Pg-upgrade2/link_requirement_spec_to_orders_created_from_quotations_created_from_requirement_spec.sql b/sql/Pg-upgrade2/link_requirement_spec_to_orders_created_from_quotations_created_from_requirement_spec.sql
new file mode 100644 (file)
index 0000000..cf549ac
--- /dev/null
@@ -0,0 +1,29 @@
+-- @tag: link_requirement_spec_to_orders_created_from_quotations_created_from_requirement_spec
+-- @description: Pflichtenhefte mit Aufträgen verknüpfen, die aus Angeboten erstellt wurden, die wiederum aus einem Pflichtenheft erstellt wurden
+-- @depends: release_3_2_0
+CREATE TEMPORARY TABLE temp_link_requirement_spec_to_orders AS
+SELECT rs_orders.requirement_spec_id, orders.id AS order_id, rs_orders.version_id
+FROM record_links rl,
+  requirement_spec_orders rs_orders,
+  oe quotations,
+  oe orders
+WHERE (rl.from_table      = 'oe')
+  AND (rl.from_id         = quotations.id)
+  AND (rl.to_table        = 'oe')
+  AND (rl.to_id           = orders.id)
+  AND (rs_orders.order_id = quotations.id)
+  AND     COALESCE(quotations.quotation, FALSE)
+  AND NOT COALESCE(orders.quotation,     FALSE)
+  AND (quotations.customer_id IS NOT NULL)
+  AND (orders.customer_id     IS NOT NULL);
+
+INSERT INTO requirement_spec_orders (requirement_spec_id, order_id, version_id)
+SELECT requirement_spec_id, order_id, version_id
+FROM temp_link_requirement_spec_to_orders new_orders
+WHERE NOT EXISTS (
+  SELECT existing_orders.id
+  FROM requirement_spec_orders existing_orders
+  WHERE (existing_orders.requirement_spec_id = new_orders.requirement_spec_id)
+    AND (existing_orders.order_id            = new_orders.order_id)
+  LIMIT 1
+);
diff --git a/sql/Pg-upgrade2/new_chart_1593_1495.sql b/sql/Pg-upgrade2/new_chart_1593_1495.sql
new file mode 100644 (file)
index 0000000..d6f83d7
--- /dev/null
@@ -0,0 +1,37 @@
+-- @tag: new_chart_1593_1495
+-- @description: Neue Konten "Verrechnungskonto erhalt. Anzahl. bei Buchung über Debitorenkonto"
+-- @depends: release_3_5_8
+
+
+DO $$
+BEGIN
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+    DECLARE
+      new_accno text := '1593';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+        INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+          VALUES (new_accno, 'Verrechnungskonto erhalt. Anzahl. bei Buchung über Debitorenkonto','A', 'L', 'AR_amount', 0);
+        INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+          VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+      END IF;
+    END;
+  END IF;
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+    DECLARE
+      new_accno text := '1495';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+        INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+          VALUES (new_accno, 'Verrechnungskonto erhalt. Anzahl. bei Buchung über Debitorenkonto','A', 'L', 'AR_amount', 0);
+        INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+          VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+      END IF;
+    END;
+  END IF;
+
+END $$;
diff --git a/sql/Pg-upgrade2/new_chart_3260_1711.sql b/sql/Pg-upgrade2/new_chart_3260_1711.sql
new file mode 100644 (file)
index 0000000..a9fb7d4
--- /dev/null
@@ -0,0 +1,37 @@
+-- @tag: new_chart_3260_1711
+-- @description: Neues Konto "Erhaltene, versteuerte Anzahlungen 7 % USt (Verbindlichkeiten)"
+-- @depends: release_3_5_8
+
+
+DO $$
+BEGIN
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+    DECLARE
+      new_accno text := '1711';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+        INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+          VALUES (new_accno, 'Erhaltene, versteuerte Anzahlungen 7 % USt (Verbindlichkeiten)','A', 'L', 'AR_amount', 0);
+        INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+          VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+      END IF;
+    END;
+  END IF;
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+    DECLARE
+      new_accno text := '3260';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+        INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+          VALUES (new_accno, 'Erhaltene, versteuerte Anzahlungen 7 % USt (Verbindlichkeiten)','A', 'L', 'AR_amount', 0);
+        INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+          VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+      END IF;
+    END;
+  END IF;
+
+END $$;
diff --git a/sql/Pg-upgrade2/new_chart_3272_1718.sql b/sql/Pg-upgrade2/new_chart_3272_1718.sql
new file mode 100644 (file)
index 0000000..24c973a
--- /dev/null
@@ -0,0 +1,37 @@
+-- @tag: new_chart_3272_1718
+-- @description: Neues Konto "Erhaltene, versteuerte Anzahlungen 19 % USt (Verbindlichkeiten)"
+-- @depends: release_3_5_8
+
+
+DO $$
+BEGIN
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR03EU' THEN
+    DECLARE
+      new_accno text := '1718';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+        INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+          VALUES (new_accno, 'Erhaltene, versteuerte Anzahlungen 19 % USt (Verbindlichkeiten)','A', 'L', 'AR_amount', 0);
+        INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+          VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+      END IF;
+    END;
+  END IF;
+
+  IF ( SELECT coa FROM defaults ) = 'Germany-DATEV-SKR04EU' THEN
+    DECLARE
+      new_accno text := '3272';
+
+    BEGIN
+      IF ( SELECT COUNT(accno) FROM chart WHERE accno LIKE new_accno ) = 0 THEN
+        INSERT INTO chart (accno, description, charttype, category, link, taxkey_id)
+          VALUES (new_accno, 'Erhaltene, versteuerte Anzahlungen 19 % USt (Verbindlichkeiten)','A', 'L', 'AR_amount', 0);
+        INSERT INTO taxkeys (chart_id, tax_id, taxkey_id, startdate)
+          VALUES ((SELECT id FROM chart WHERE accno LIKE new_accno), 0, 0, '1970-01-01');
+      END IF;
+    END;
+  END IF;
+
+END $$;
diff --git a/sql/Pg-upgrade2/record_links_remove_to_quotation.pl b/sql/Pg-upgrade2/record_links_remove_to_quotation.pl
new file mode 100644 (file)
index 0000000..e926006
--- /dev/null
@@ -0,0 +1,51 @@
+# @tag: record_links_remove_to_quotation
+# @description: Verknüpfte Positionen mit Ziel Angebot und dazugehörige Belegverknüpfung entfernen, wenn Quelle Angebot oder Auftrag.
+# @depends: release_3_6_0
+package SL::DBUpgrade2::record_links_remove_to_quotation;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+use SL::DBUtils;
+
+sub run {
+  my ($self) = @_;
+
+  my $query = qq|SELECT record_links.id AS rl_id, from_oe.id AS from_oe_id, to_oe.id AS to_oe_id FROM record_links
+                   LEFT JOIN orderitems from_oi ON (from_oi.id = from_id)
+                   LEFT JOIN orderitems to_oi   ON (to_oi.id   = to_id)
+                   LEFT JOIN oe         from_oe ON (from_oe.id = from_oi.trans_id)
+                   LEFT JOIN oe         to_oe   ON (to_oe.id   = to_oi.trans_id)
+                 WHERE from_table = 'orderitems'
+                   AND to_table   = 'orderitems'
+                   AND to_oe.quotation IS TRUE|;
+
+  my $refs = selectall_hashref_query($::form, $self->dbh, $query);
+
+  my $query_delete_oi_links = qq|
+    DELETE FROM record_links WHERE id = ?;
+  |;
+  my $sth_delete_oi_links = $self->dbh->prepare($query_delete_oi_links);
+
+  my $query_delete_oe_links = qq|
+    DELETE FROM record_links WHERE from_table = 'oe' AND to_table = 'oe' AND from_id = ? AND to_id = ?;
+  |;
+  my $sth_delete_oe_links = $self->dbh->prepare($query_delete_oe_links);
+
+  my %oe_links;
+  foreach my $ref (@$refs) {
+    $sth_delete_oi_links->execute($ref->{rl_id}) || $::form->dberror($query_delete_oi_links);
+    $oe_links{$ref->{from_oe_id} . ':' . $ref->{to_oe_id}} = 1;
+  }
+
+  for my $from_to (keys %oe_links) {
+    my ($from_oe_id, $to_oe_id) = split ':', $from_to;
+    $sth_delete_oe_links->execute($from_oe_id, $to_oe_id) || $::form->dberror($query_delete_oe_links);
+  }
+
+  return 1;
+}
+
+1;
diff --git a/sql/Pg-upgrade2/release_3_6_0.sql b/sql/Pg-upgrade2/release_3_6_0.sql
new file mode 100644 (file)
index 0000000..3ca833a
--- /dev/null
@@ -0,0 +1,3 @@
+-- @tag: release_3_6_0
+-- @description: Leeres Script, das alle Upgradescripte bis zum Release 3.6.0 voraussetzt, um ein fest definiertes Schema zu definieren.
+-- @depends: release_3_5_8 defaults_advance_payment_transfer_charts link_requirement_spec_to_orders_created_from_quotations_created_from_requirement_spec deliveryorder_type defaults_print_interpolate_variables_in_positions file_storage_partial_invoices defaults_qrbill_variants defaults_sales_purchase_record_numbers_changeable ar_add_qrbill_without_amount defaults_view_record_links convert_columns_to_html_for_sending_html_emails2 defaults_partsgroup_required defaults_order_warn_no_cusordnumber files_add_variant custom_variables_convert_width_height_to_pixels deliveryorder_transnumbers shop_add_proxy bank_account_information_for_swiss_qrbill defaults_order_controller customer_remove_empty_additional_billing_addresses shop_orders_update_4 defaults_invoice_warn_no_delivery_order
diff --git a/sql/Pg-upgrade2/release_3_6_1.sql b/sql/Pg-upgrade2/release_3_6_1.sql
new file mode 100644 (file)
index 0000000..e4b43cb
--- /dev/null
@@ -0,0 +1,3 @@
+-- @tag: release_3_6_1
+-- @description: Leeres Script, das alle Upgradescripte bis zum Release 3.6.1 voraussetzt, um ein fest definiertes Schema zu definieren.
+-- @depends: release_3_6_0 tax_reverse_charge_key_19 delete_wrong_charts_for_taxkeys delete_wrong_charts_for_taxkeys_04 defaults_invoice_prevent_browser_back file_full_texts remove_oids language_obsolete add_record_templates_transaction_description full_texts_background_job tax_reverse_charge_key_18 record_links_remove_to_quotation convert_real_qty ap_gl add_gl_transaction_description
diff --git a/sql/Pg-upgrade2/remove_oids.sql b/sql/Pg-upgrade2/remove_oids.sql
new file mode 100644 (file)
index 0000000..9e9f439
--- /dev/null
@@ -0,0 +1,9 @@
+-- @tag: remove_oids
+-- @description: OIDs von Tabellen entfernen
+-- @depends: release_3_6_0
+ALTER TABLE assembly             SET WITHOUT OIDS;
+ALTER TABLE delivery_order_items SET WITHOUT OIDS;
+ALTER TABLE invoice              SET WITHOUT OIDS;
+ALTER TABLE orderitems           SET WITHOUT OIDS;
+ALTER TABLE parts                SET WITHOUT OIDS;
+ALTER TABLE partsgroup           SET WITHOUT OIDS;
diff --git a/sql/Pg-upgrade2/shop_orders_update_4.sql b/sql/Pg-upgrade2/shop_orders_update_4.sql
new file mode 100644 (file)
index 0000000..93324fb
--- /dev/null
@@ -0,0 +1,8 @@
+-- @tag: shop_orders_update_4
+-- @description: Ändern der Tabellen shop_orders, shop_trans_id darf auch Text enthalten
+-- @depends: shop_orders_update_1 shop_orders_update_2 shop_orders_update_3
+
+-- @ignore: 0
+
+ALTER TABLE shop_orders ALTER COLUMN shop_trans_id TYPE text;
+ALTER TABLE shop_order_items ALTER COLUMN shop_trans_id TYPE text;
diff --git a/sql/Pg-upgrade2/shops_5.sql b/sql/Pg-upgrade2/shops_5.sql
new file mode 100644 (file)
index 0000000..72b4355
--- /dev/null
@@ -0,0 +1,6 @@
+-- @tag: shops_5
+-- @description: Shop-Config um Option zur direkten Beschreibungsübernahme erweitern
+-- @depends: shop_4
+-- @ignore: 0
+
+ALTER TABLE shops ADD COLUMN use_part_longdescription BOOLEAN default false;
diff --git a/sql/Pg-upgrade2/shops_6.sql b/sql/Pg-upgrade2/shops_6.sql
new file mode 100644 (file)
index 0000000..788bdb9
--- /dev/null
@@ -0,0 +1,6 @@
+-- @tag: shop_add_proxy
+-- @description: Shop-Config um Option Proxy erweitert
+-- @depends: shops_5
+-- @ignore: 0
+
+ALTER TABLE shops ADD COLUMN proxy TEXT default '';
diff --git a/sql/Pg-upgrade2/tax_reverse_charge.sql b/sql/Pg-upgrade2/tax_reverse_charge.sql
new file mode 100644 (file)
index 0000000..91ba9c1
--- /dev/null
@@ -0,0 +1,109 @@
+-- @tag: tax_reverse_charge
+-- @description: Reverse Charge für Kreditorenbelege
+-- @depends: release_3_6_0
+-- @ignore: 0
+
+ALTER TABLE tax add column reverse_charge_chart_id integer;
+
+INSERT INTO chart (
+  accno, description,
+  charttype,   category,  link,
+  taxkey_id
+  )
+SELECT
+  '1577','Abziehbare Vorst. nach §13b UstG 19%',
+  'A',         'E',       'AP_tax:IC_taxpart:IC_taxservice',
+  0
+WHERE EXISTS ( -- update only for SKR03
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR03EU' AND NOT EXISTS (SELECT id from chart where accno='1577')
+);
+
+INSERT INTO chart (
+  accno, description,
+  charttype,   category,  link,
+  taxkey_id
+  )
+SELECT
+  '1787','Umsatzsteuer nach §13b UStG 19%',
+  'A',         'I',       'AR_tax:IC_taxpart:IC_taxservice',
+  0
+WHERE EXISTS ( -- update only for SKR03
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR03EU' AND NOT EXISTS (SELECT id from chart where accno='1787')
+);
+
+
+INSERT INTO chart (
+  accno, description,
+  charttype,   category,  link,
+  taxkey_id
+  )
+SELECT
+  '1407','Abziehbare Vorst. nach §13b UstG 19%',
+  'A',         'E',       'AP_tax:IC_taxpart:IC_taxservice',
+  0
+WHERE EXISTS ( -- update only for SKR04
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR04EU' AND NOT EXISTS (SELECT id from chart where accno='1407')
+);
+
+INSERT INTO chart (
+  accno, description,
+  charttype,   category,  link,
+  taxkey_id
+  )
+SELECT
+  '3837','Umsatzsteuer nach §13b UStG 19%',
+  'A',         'I',       'AR_tax:IC_taxpart:IC_taxservice',
+  0
+WHERE EXISTS ( -- update only for SKR04
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR04EU' AND NOT EXISTS (SELECT id from chart where accno='3837')
+);
+
+
+
+INSERT INTO tax (
+  chart_id,
+  reverse_charge_chart_id,
+  rate,
+  taxkey,
+  taxdescription,
+  chart_categories
+  )
+  SELECT
+  (SELECT id FROM chart WHERE accno = '1577'),
+  (SELECT id FROM chart WHERE accno = '1787'), 0,
+  '94', '19% Vorsteuer und 19% Umsatzsteuer', 'EI'
+WHERE EXISTS ( -- update only for SKR03
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR03EU'
+);
+
+
+INSERT INTO tax (
+  chart_id,
+  reverse_charge_chart_id,
+  rate,
+  taxkey,
+  taxdescription,
+  chart_categories
+  )
+  SELECT
+  (SELECT id FROM chart WHERE accno = '1407'),
+  (SELECT id FROM chart WHERE accno = '3837'), 0,
+  '94', '19% Vorsteuer und 19% Umsatzsteuer', 'EI'
+WHERE EXISTS ( -- update only for SKR03
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR04EU'
+);
+
+-- if not defined
+insert into taxkeys(chart_id,tax_id,taxkey_id,startdate) SELECT (SELECT chart_id FROM tax WHERE taxkey = '94'),0,0,'1970-01-01' WHERE NOT EXISTS
+  (SELECT chart_id from taxkeys where chart_id = ( SELECT chart_id FROM tax WHERE taxkey = '94'))
+  AND (EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR04EU') OR EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR03EU'));
+
+insert into taxkeys(chart_id,tax_id,taxkey_id,startdate) SELECT (SELECT reverse_charge_chart_id FROM tax WHERE taxkey = '94'),0,0,'1970-01-01' WHERE NOT EXISTS
+  (SELECT chart_id from taxkeys where chart_id = ( SELECT reverse_charge_chart_id FROM tax WHERE taxkey = '94'))
+    AND (EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR04EU') OR EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR03EU'));
diff --git a/sql/Pg-upgrade2/tax_reverse_charge_key_18.sql b/sql/Pg-upgrade2/tax_reverse_charge_key_18.sql
new file mode 100644 (file)
index 0000000..f67eff3
--- /dev/null
@@ -0,0 +1,51 @@
+-- @tag: tax_reverse_charge_key_18
+-- @description: Reverse Charge für Kreditorenbelege Steuerschlüssel 18
+-- @depends: release_3_6_0 clean_tax_18_19
+-- @ignore: 0
+
+INSERT INTO tax (
+  chart_id,
+  reverse_charge_chart_id,
+  rate,
+  taxkey,
+  taxdescription,
+  chart_categories
+  )
+  SELECT
+  (SELECT id FROM chart WHERE accno = '1572'),
+  (SELECT id FROM chart WHERE accno = '1772'), 0.07,
+  '18', 'Stpf. innergemeinschaftlicher Erwerb zum verminderten Vor- und Ust.-satz', 'EI'
+WHERE EXISTS ( -- update only for SKR03
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR03EU'
+);
+
+
+INSERT INTO tax (
+  chart_id,
+  reverse_charge_chart_id,
+  rate,
+  taxkey,
+  taxdescription,
+  chart_categories
+  )
+  SELECT
+  (SELECT id FROM chart WHERE accno = '1402'),
+  (SELECT id FROM chart WHERE accno = '3802'), 0.07,
+  '18', 'Stpf. innergemeinschaftlicher Erwerb zum verminderten Vor- und Ust.-satz', 'EI'
+WHERE EXISTS ( -- update only for SKR04
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR04EU'
+);
+
+
+-- if not defined
+insert into taxkeys(chart_id,tax_id,taxkey_id,startdate) SELECT (SELECT reverse_charge_chart_id FROM tax WHERE taxkey = '18' and rate = 0.07 and reverse_charge_chart_id is not null),0,0,'1970-01-01' WHERE NOT EXISTS
+  (SELECT chart_id from taxkeys where chart_id = ( SELECT reverse_charge_chart_id FROM tax WHERE taxkey = '18' and rate = 0.07 and reverse_charge_chart_id is not null))
+  AND (EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR04EU') OR EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR03EU'));
+
+-- if not defined
+insert into taxkeys(chart_id,tax_id,taxkey_id,startdate) SELECT (SELECT chart_id FROM tax WHERE taxkey = '18' and rate = 0.07 and reverse_charge_chart_id is not null),0,0,'1970-01-01' WHERE NOT EXISTS
+  (SELECT chart_id from taxkeys where chart_id = ( SELECT chart_id FROM tax WHERE taxkey = '18' and rate = 0.07 and reverse_charge_chart_id is not null))
+  AND (EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR04EU') OR EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR03EU'));
+
diff --git a/sql/Pg-upgrade2/tax_reverse_charge_key_19.sql b/sql/Pg-upgrade2/tax_reverse_charge_key_19.sql
new file mode 100644 (file)
index 0000000..c4b4a68
--- /dev/null
@@ -0,0 +1,65 @@
+-- @tag: tax_reverse_charge_key_19
+-- @description: Reverse Charge für Kreditorenbelege Steuerschlüssel 19
+-- @depends: release_3_6_0 clean_tax_18_19
+-- @ignore: 0
+
+UPDATE tax set rate=0.19 where taxkey=94 AND reverse_charge_chart_id is not NULL;
+
+INSERT INTO chart (
+  accno, description,
+  charttype,   category,  link,
+  taxkey_id
+  )
+SELECT
+  '1774','Umsatzsteuer aus innergemeinschftl. Erwerb 19%',
+  'A',         'I',       'AR_tax:IC_taxpart:IC_taxservice',
+  0
+WHERE EXISTS ( -- update only for SKR03
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR03EU' AND NOT EXISTS (SELECT id from chart where accno='1774')
+);
+
+INSERT INTO tax (
+  chart_id,
+  reverse_charge_chart_id,
+  rate,
+  taxkey,
+  taxdescription,
+  chart_categories
+  )
+  SELECT
+  (SELECT id FROM chart WHERE accno = '1574'),
+  (SELECT id FROM chart WHERE accno = '1774'), 0.19,
+  '19', 'Stpf. innergemeinschaftlicher Erwerb zum vollem Vor- und Ust.-satz', 'EI'
+WHERE EXISTS ( -- update only for SKR03
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR03EU'
+);
+
+
+INSERT INTO tax (
+  chart_id,
+  reverse_charge_chart_id,
+  rate,
+  taxkey,
+  taxdescription,
+  chart_categories
+  )
+  SELECT
+  (SELECT id FROM chart WHERE accno = '1404'),
+  (SELECT id FROM chart WHERE accno = '3804'), 0.19,
+  '19', 'Stpf. innergemeinschaftlicher Erwerb zum vollem Vor- und Ust.-satz', 'EI'
+WHERE EXISTS ( -- update only for SKR04
+    SELECT coa FROM defaults
+    WHERE defaults.coa='Germany-DATEV-SKR04EU'
+);
+
+-- if not defined
+insert into taxkeys(chart_id,tax_id,taxkey_id,startdate) SELECT (SELECT reverse_charge_chart_id FROM tax WHERE taxkey = '19' and rate = 0.19 and reverse_charge_chart_id is not null),0,0,'1970-01-01' WHERE NOT EXISTS
+  (SELECT chart_id from taxkeys where chart_id = ( SELECT reverse_charge_chart_id FROM tax WHERE taxkey = '19' and rate = 0.19 and reverse_charge_chart_id is not null))
+  AND (EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR04EU') OR EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR03EU'));
+-- if not defined
+insert into taxkeys(chart_id,tax_id,taxkey_id,startdate) SELECT (SELECT chart_id FROM tax WHERE taxkey = '19' and rate = 0.19 and reverse_charge_chart_id is not null),0,0,'1970-01-01' WHERE NOT EXISTS
+  (SELECT chart_id from taxkeys where chart_id = ( SELECT chart_id FROM tax WHERE taxkey = '19' and rate = 0.19 and reverse_charge_chart_id is not null))
+  AND (EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR04EU') OR EXISTS (SELECT coa FROM defaults WHERE defaults.coa='Germany-DATEV-SKR03EU'));
+
diff --git a/sql/mebil.sql b/sql/mebil.sql
new file mode 100644 (file)
index 0000000..db92f51
--- /dev/null
@@ -0,0 +1,98 @@
+-- Table of mebil extensions
+-- for module 
+-- Lx office
+DROP TABLE IF EXISTS mebil_mapping;
+CREATE TABLE mebil_mapping (
+       id                      SERIAL PRIMARY KEY,
+       ordering        INTEGER NOT NULL,
+       typ                     CHAR NOT NULL,
+       fromacc         VARCHAR(200) NOT NULL,
+       toacc           VARCHAR(200) NOT NULL
+);
+INSERT INTO mebil_mapping (ordering,typ,fromacc,toacc)
+VALUES
+       (10,'S','0483','bs.ass.fixAss.tan.machinery.gwgsammelposten'),
+       (10,'S','0484','bs.ass.fixAss.tan.machinery.gwgsammelposten'),
+       (20,'X','bs.ass.fixAss.tan.machinery.gwgsammelposten','bs.ass.fixAss.tan.machinery'),
+       (21,'X','bs.ass.fixAss.tan.machinery','bs.ass.fixAss.tan'),
+       (22,'X','bs.ass.fixAss.tan','bs.ass.fixAss'),
+       (50,'X','bs.ass.fixAss','bs.ass'),
+
+   (10,'S','1200','bs.ass.currAss.cashEquiv.bank'),
+   (20,'X','bs.ass.currAss.cashEquiv.bank','bs.ass.currAss.cashEquiv'),
+   (21,'X','bs.ass.currAss.cashEquiv.bank','bs.ass.currAss'),
+
+       (10,'S','3980','bs.ass.currAss.inventory.finishedAndMerch.merchandise.new'),
+       (20,'X','bs.ass.currAss.inventory.finishedAndMerch.merchandise.new','bs.ass.currAss.inventory.finishedAndMerch.merchandise'),
+       (21,'X','bs.ass.currAss.inventory.finishedAndMerch.merchandise','bs.ass.currAss.inventory.finishedAndMerch'),
+       (22,'X','bs.ass.currAss.inventory.finishedAndMerch','bs.ass.currAss.inventory'),
+       (23,'X','bs.ass.currAss.inventory','bs.ass.currAss'),
+
+       (10,'S','1400','bs.ass.currAss.receiv.trade'),
+       (20,'X','bs.ass.currAss.receiv.trade','bs.ass.currAss.receiv'),
+
+       (10,'S','1575','bs.ass.currAss.receiv.other.vat'),
+       (10,'S','1576','bs.ass.currAss.receiv.other.vat'),
+       (10,'S','1579','bs.ass.currAss.receiv.other.vat'),
+       (10,'S','1780','bs.ass.currAss.receiv.other.vat'),
+       (20,'X','bs.ass.currAss.receiv.other.vat','bs.ass.currAss.receiv.other'),
+       (21,'X','bs.ass.currAss.receiv.other','bs.ass.currAss.receiv'),
+       (30,'X','bs.ass.currAss.receiv','bs.ass.currAss'),
+
+       (50,'X','bs.ass.currAss','bs.ass'),
+       
+       (10,'H','0800','bs.eqLiab.equity.subscribed.corp'),
+       (20,'X',       'bs.eqLiab.equity.subscribed.corp','bs.eqLiab.equity.subscribed'),
+       (40,'X',       'bs.eqLiab.equity.subscribed',     'bs.eqLiab.equity'),
+       (10,'H','0810','bs.eqLiab.equity.capRes'),
+       (20,'X',       'bs.eqLiab.equity.capRes',         'bs.eqLiab.equity'),
+       (50,'X',       'bs.eqLiab.equity',                'bs.eqLiab'),
+       (10,'H','0970','bs.eqLiab.accruals.other.upTo1year'),
+       (20,'X',       'bs.eqLiab.accruals.other.upTo1year','bs.eqLiab.accruals.other'),
+       (21,'X',       'bs.eqLiab.accruals.other','bs.eqLiab.accruals'),
+       (50,'X',       'bs.eqLiab.accruals','bs.eqLiab'),
+       (10,'H','1775','bs.eqLiab.liab.other.theroffTax.vat'),
+       (10,'H','1776','bs.eqLiab.liab.other.theroffTax.vat'),
+       (20,'X',       'bs.eqLiab.liab.other.theroffTax.vat','bs.eqLiab.liab.other.theroffTax'),
+       (10,'H','1651','bs.eqLiab.liab.other.theroffTax.operatingTaxes'),
+       (10,'H','1652','bs.eqLiab.liab.other.theroffTax.operatingTaxes'),
+       (10,'H','1653','bs.eqLiab.liab.other.theroffTax.operatingTaxes'),
+       (20,'X',       'bs.eqLiab.liab.other.theroffTax.operatingTaxes','bs.eqLiab.liab.other.theroffTax'),
+       (21,'X',       'bs.eqLiab.liab.other.theroffTax','bs.eqLiab.liab.other'),
+       (10,'H','1606','bs.eqLiab.liab.other.profitPartLoans'),
+       (20,'X',       'bs.eqLiab.liab.other.profitPartLoans','bs.eqLiab.liab.other'),
+       (22,'X',       'bs.eqLiab.liab.other','bs.eqLiab.liab'),
+       (50,'X',       'bs.eqLiab.liab','bs.eqLiab'),
+       
+       (10,'S','4121','is.netIncome.regular.operatingTC.staff.salaries.managerPartner'),
+       (20,'X'       ,'is.netIncome.regular.operatingTC.staff.salaries.managerPartner','is.netIncome.regular.operatingTC.staff.salaries'),
+       (21,'X'       ,'is.netIncome.regular.operatingTC.staff.salaries','ismi.netIncome.staff'),
+       (50,'Y'       ,'ismi.netIncome.staff','ismi.netIncome'),
+       (10,'S','3960','is.netIncome.regular.operatingTC.grossTradingProfit.materialServices.material.purchased.generalRateVAT'),
+       (20,'X',       'is.netIncome.regular.operatingTC.grossTradingProfit.materialServices.material.purchased.generalRateVAT','is.netIncome.regular.operatingTC.grossTradingProfit.materialServices.material.purchased'),
+       (21,'X',       'is.netIncome.regular.operatingTC.grossTradingProfit.materialServices.material.purchased','is.netIncome.regular.operatingTC.grossTradingProfit.materialServices.material'),
+       (22,'X',       'is.netIncome.regular.operatingTC.grossTradingProfit.materialServices.material','ismi.netIncome.materialServices'),
+       (50,'Y',       'ismi.netIncome.materialServices','ismi.netIncome'),
+       
+       (50,'X','bs.ass.fixAss.tan.machinery.gwgsammelposten','all'),
+       (10,'R','ACC=0482:START=2016:VALUES=negative','grossCost.beginning'),
+       (10,'R','ACC=0484:START=2017:VALUES=negative','grossCost.beginning'),
+       (50,'X','grossCost.beginning','gross'),
+       (50,'X','gross.addition','gross'),
+       (10,'R','ACC=0483:START=YEAR:VALUES=negative','gross.addition'),
+       (52,'X','grossCost.beginning','accDepr'),
+       (52,'X','gross.addition','accDepr'),
+       (52,'Y','all','accDepr'),
+       (50,'X','grossCost.beginning','accDepr.beginning'),
+       (50,'Y','all_Prev_period','accDepr.beginning'),
+       (50,'X','all_Prev_period','accDepr.DeprPeriod'),
+       (50,'X','gross.addition','accDepr.DeprPeriod'),
+       (50,'Y','all','accDepr.DeprPeriod'),
+       (60,'X','accDepr.DeprPeriod','accDepr.DeprPeriod.regular'),
+       (10,'R','ACC=0482:END=PY:INVERT=true','all_Prev_period'),
+       (10,'R','ACC=0483:END=PY:INVERT=true','all_Prev_period'),
+       (10,'R','ACC=0484:END=PY:INVERT=true','all_Prev_period'),
+       
+       (0,'C','de-gaap-ci.bsAss','hbst.transfer.bsAss.name')
+       ;
+
index e79429b..92f9362 100644 (file)
@@ -1,4 +1,4 @@
-use Test::More tests => 291;
+use Test::More tests => 293;
 
 use strict;
 
@@ -177,7 +177,7 @@ sub reset_state {
 
 sub test_ar_transaction {
   my (%params) = @_;
-  my $netamount = $params{amount} || 100;
+  my $netamount = $::form->round_amount($params{amount}, 2) || 100;
   my $amount    = $::form->round_amount($netamount * 1.19,2);
   my $invoice   = SL::DB::Invoice->new(
       invoice      => 0,
@@ -335,7 +335,8 @@ sub test_bt_error {
   $::form->{invoice_skontos} = {
     $bt->id => [ 'with_skonto_pt' ]
   };
-
+  is($ar_transaction->netamount, $::form->round_amount(168.58/1.19, 2), "$testname: Net Amount assigned");
+  is($ar_transaction->amount, 168.58, "$testname: Amount assigned");
   is($ar_transaction->paid   , '0' , "$testname: salesinv is not paid");
 
   # generate an error for testing rollback mechanism
@@ -626,7 +627,7 @@ sub test_full_workflow_ar_multiple_inv_skonto_reconciliate_and_undo {
   is($bt->invoice_amount   , '299.29000' , "$testname: bt invoice amount was assigned partially paid amount");
   is($bt->amount           , '299.29000' , "$testname: bt amount is stil there");
   is(scalar @{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt->id ] )},
-       7, "$testname 7 acc_trans entries created");
+       9, "$testname 9 acc_trans entries created");
 
   # same loop as above, but only for the 3rd ar_id
   foreach my $acc_trans_id_entry (@{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [ar_id => $ar_transaction_skonto->id ] )}) {
diff --git a/t/controllers/csvimport/delivery_orders.t b/t/controllers/csvimport/delivery_orders.t
new file mode 100644 (file)
index 0000000..ca38c2d
--- /dev/null
@@ -0,0 +1,282 @@
+use Test::More tests => 28;
+
+use strict;
+
+use lib 't';
+use utf8;
+
+use Support::TestSetup;
+
+use List::MoreUtils qw(none any);
+
+use SL::Controller::CsvImport;
+use_ok 'SL::Controller::CsvImport::DeliveryOrder';
+
+use SL::Dev::ALL qw(:ALL);
+
+Support::TestSetup::login();
+
+#####
+sub do_import {
+  my ($file, $settings) = @_;
+
+  my $controller = SL::Controller::CsvImport->new(
+    type => 'delivery_orders',
+  );
+  $controller->load_default_profile;
+  $controller->profile->set(
+    charset  => 'utf-8',
+    sep_char => ';',
+    %$settings
+  );
+
+  my $worker = SL::Controller::CsvImport::DeliveryOrder->new(
+    controller => $controller,
+    file       => $file,
+  );
+  $worker->run(test => 0);
+
+  return if $worker->controller->errors;
+
+  # don't try and save objects that have errors
+  $worker->save_objects unless scalar @{$worker->controller->data->[0]->{errors}};
+
+  return $worker->controller->data;
+}
+
+sub clear_up {
+  foreach (qw(RecordLink Order DeliveryOrder Customer Part)) {
+    "SL::DB::Manager::${_}"->delete_all(all => 1);
+  }
+  SL::DB::Manager::Employee->delete_all(where => [ '!login' => 'unittests' ]);
+}
+
+#####
+
+# set numberformat and locale (so we can match errors)
+my $old_numberformat      = $::myconfig{numberformat};
+$::myconfig{numberformat} = '1.000,00';
+my $old_locale            = $::locale;
+$::locale                 = Locale->new('en');
+
+clear_up;
+
+#####
+my @customers;
+my @parts;
+my @orders;
+my $file;
+my $entries;
+my $entry;
+
+# simple import
+@customers = (new_customer(name => 'TestCustomer1', discount => 0)->save);
+@parts = (
+  new_part(description => 'TestPart1', ean => '')->save,
+  new_part(description => 'TestPart2', ean => '')->save
+);
+
+$file = \<<EOL;
+datatype;customer
+datatype;description;qty
+datatype
+DeliveryOrder;TestCustomer1
+OrderItem;TestPart1;5
+OrderItem;TestPart2;10
+EOL
+
+$entries = do_import($file);
+
+$entry = $entries->[0];
+is $entry->{object}->customer_id, $customers[0]->id, 'simple import: customer_id';
+
+$entry = $entries->[1];
+is $entry->{object}->parts_id,    $parts[0]->id,     'simple import: part 1: parts_id';
+is $entry->{object}->qty,         5,                 'simple import: part 1: qty';
+
+$entry = $entries->[2];
+is $entry->{object}->parts_id,    $parts[1]->id,     'simple import: part 2: parts_id';
+is $entry->{object}->qty,         10,                'simple import: part 2: qty';
+
+
+$entries = undef;
+clear_up;
+
+#####
+# with source order
+@customers = (new_customer(name => 'TestCustomer1', discount => 0)->save);
+@parts = (
+  new_part(description => 'TestPart1', ean => '')->save,
+  new_part(description => 'TestPart2', ean => '')->save,
+  new_part(description => 'TestPart3', ean => '')->save
+);
+@orders = (
+  create_sales_order(
+    save       => 1,
+    customer   => $customers[0],
+    ordnumber  => '1234',
+    orderitems => [ create_order_item(part => $parts[0], qty =>  3, sellprice => 70),
+                    create_order_item(part => $parts[1], qty => 10, sellprice => 50),
+                    create_order_item(part => $parts[2], qty =>  8, sellprice => 80),
+                    create_order_item(part => $parts[2], qty => 11, sellprice => 80)
+    ]
+  )
+);
+
+$file = \<<EOL;
+datatype;customer;ordnumber
+datatype;description;qty
+datatype
+DeliveryOrder;TestCustomer1;1234
+OrderItem;TestPart1;5
+OrderItem;TestPart2;10
+OrderItem;TestPart3;7
+OrderItem;TestPart3;1
+OrderItem;TestPart3;11
+EOL
+
+  1;                            # make emacs happy
+
+# should be:
+# delivery oder pos/qty <- order pos/qty
+#       1/5             <-       -
+#       2/10            <-      2/10
+#       3/7             <-      3/7
+#       4/1             <-      3/1
+#       5/11            <-      4/11
+
+$entries = do_import($file);
+$orders[0]->load;               # reload order to get correct delivered status
+
+$entry = $entries->[0];
+is $entry->{object}->ordnumber, '1234', 'with source order: ordnumber';
+
+my $linked = $orders[0]->linked_records(to => 'DeliveryOrder');
+ok(scalar @$linked == 1, 'with source order: order linked to one delivery order');
+ok($linked->[0]->id == $entry->{object}->id, 'with source order: order linked to imported delivery order');
+
+
+$linked = $entry->{object}->linked_records(from => 'Order');
+ok(scalar @$linked == 1, 'with source order: delivery order linked from one order');
+ok($linked->[0]->id == $orders[0]->id, 'with source order: delivery order linked from source order');
+
+$entry = $entries->[1];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok(scalar @$linked == 0, 'with source order: delivered qty > ordered qty: delivery order item not linked');
+
+$entry = $entries->[2];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok(scalar @$linked == 1, 'with source order: same qtys: delivery order item linked');
+ok($linked->[0]->id == $orders[0]->items_sorted->[1]->id, 'with source order: same qtys: delivery order item linked from source order item');
+
+$entry = $entries->[3];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok(scalar @$linked == 1, 'with source order: delivered qty < ordered qty: delivery order item linked (fill up)');
+ok($linked->[0]->position == 3, 'with source order: delivered qty < ordered qty: order position ok (fill up)');
+
+$entry = $entries->[4];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok(scalar @$linked == 1, 'with source order: delivered qty < ordered qty: delivery order item linked (fill up) 2');
+ok($linked->[0]->position == 3, 'with source order: delivered qty < ordered qty: order position ok (fill up) 2');
+
+$entry = $entries->[5];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok(scalar @$linked == 1, 'with source order: delivered qty == ordered qty: found exact match after fill up');
+ok($linked->[0]->position == 4, 'with source order: delivered qty == ordered qty: order position ok after fill up');
+
+ok(!$orders[0]->delivered, 'with source order: order not completely delivered');
+
+$entries = undef;
+clear_up;
+
+#####
+@customers = (new_customer(name => 'TestCustomer1', discount => 0)->save);
+@parts = (
+  new_part(description => 'TestPart1', ean => '')->save,
+  new_part(description => 'TestPart2', ean => '')->save,
+  new_part(description => 'TestPart3', ean => '')->save
+);
+@orders = (
+  create_sales_order(
+    save       => 1,
+    customer   => $customers[0],
+    ordnumber  => '1234',
+    orderitems => [ create_order_item(part => $parts[0], qty =>  3, sellprice => 70),
+                    create_order_item(part => $parts[1], qty => 10, sellprice => 50),
+                    create_order_item(part => $parts[2], qty =>  8, sellprice => 80),
+                    create_order_item(part => $parts[2], qty => 11, sellprice => 80)
+    ]
+  )
+);
+
+$file = \<<EOL;
+datatype;customer;ordnumber
+datatype;description;qty
+datatype
+DeliveryOrder;TestCustomer1;1234
+OrderItem;TestPart1;1
+OrderItem;TestPart2;10
+OrderItem;TestPart1;2
+OrderItem;TestPart3;7
+OrderItem;TestPart3;11
+OrderItem;TestPart3;1
+
+EOL
+
+  1;                            # make emacs happy
+
+# should be:
+# delivery oder pos/qty <- order pos/qty
+#       1/1             <-      1/1
+#       2/10            <-      2/10
+#       3/2             <-      1/2
+#       4/7             <-      3/7
+#       5/11            <-      4/11
+#       6/1             <-      3/1
+
+$entries = do_import($file);
+$orders[0]->load;               # reload order to get correct delivered status
+
+$entry = $entries->[1];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok($linked->[0]->position == 1, 'with source order: mixed qtys and fill up: order position ok 1');
+
+$entry = $entries->[2];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok($linked->[0]->position == 2, 'with source order: mixed qtys and fill up: order position ok 2');
+
+$entry = $entries->[3];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok($linked->[0]->position == 1, 'with source order: mixed qtys and fill up: order position ok 3');
+
+$entry = $entries->[4];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok($linked->[0]->position == 3, 'with source order: mixed qtys and fill up: order position ok 4');
+
+$entry = $entries->[5];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok($linked->[0]->position == 4, 'with source order: mixed qtys and fill up: order position ok 5');
+
+$entry = $entries->[6];
+$linked = $entry->{object}->linked_records(from => 'OrderItem');
+ok($linked->[0]->position == 3, 'with source order: mixed qtys and fill up: order position ok 6');
+
+ok(!!$orders[0]->delivered, 'with source order: mixed qtys and fill up: order completely delivered');
+
+#####
+$entries = undef;
+clear_up;
+
+#####
+
+$::myconfig{numberformat} = $old_numberformat;
+$::locale                 = $old_locale;
+
+1;
+
+#####
+# vim: ft=perl
+# set emacs to perl mode
+# Local Variables:
+# mode: perl
+# End:
diff --git a/t/controllers/csvimport/inventory.t b/t/controllers/csvimport/inventory.t
new file mode 100644 (file)
index 0000000..1492323
--- /dev/null
@@ -0,0 +1,384 @@
+use strict;
+
+use Data::Dumper; # maybe in Tests available?
+use Test::Deep qw(cmp_deeply superhashof ignore);
+use Test::More;
+use Test::Exception;
+
+use lib 't';
+
+use SL::Dev::Part qw(new_part new_assembly new_service);
+use SL::Dev::Inventory qw(create_warehouse_and_bins set_stock);
+
+use_ok 'Support::TestSetup';
+use_ok 'SL::Controller::CsvImport';
+use_ok 'SL::DB::Bin';
+use_ok 'SL::DB::Part';
+use_ok 'SL::DB::Warehouse';
+use_ok 'SL::DB::Inventory';
+use_ok 'SL::WH';
+use_ok 'SL::Helper::Inventory';
+
+Support::TestSetup::login();
+
+my ($wh, $bin1, $bin2, $assembly1, $assembly_service, $part1, $part2, $wh_moon, $bin_moon, $service1);
+
+sub reset_state {
+  # Create test data
+
+  clear_up();
+  create_standard_stock();
+
+}
+reset_state();
+
+#####
+sub test_import {
+  my ($file,$settings) = @_;
+
+  my $controller = SL::Controller::CsvImport->new(
+    type => 'inventories'
+  );
+  $controller->load_default_profile;
+  $controller->profile->set(
+    charset      => 'utf-8',
+    sep_char     => ',',
+    quote_char   => '"',
+    numberformat => $::myconfig{numberformat},
+  );
+  my $csv_inventory_import = SL::Controller::CsvImport::Inventory->new(
+    settings   => $settings,
+    controller => $controller,
+    file       => $file,
+  );
+  #print "profile param type=".$csv_part_import->settings->{parts_type}."\n";
+
+  $csv_inventory_import->run(test => 0);
+
+  # don't try and save objects that have errors
+  $csv_inventory_import->save_objects unless scalar @{$csv_inventory_import->controller->data->[0]->{errors}};
+
+  return $csv_inventory_import->controller->data;
+}
+
+$::myconfig{numberformat} = '1000.00';
+my $old_locale = $::locale;
+# set locale to en so we can match errors
+$::locale = Locale->new('en');
+
+
+my ($entries, $entry, $file);
+
+# different settings for tests
+#
+
+my $settings1 = {
+                  apply_comment => 'missing',
+                  comment       => 'Lager Inventur Standard',
+                };
+#
+#
+# starting test of csv imports
+# to debug errors in certain tests, run after test_import:
+#   die Dumper($entry->{errors});
+
+
+##### create complete bullshit
+$file = \<<EOL;
+bin,chargenumber,comment,employee_id,partnumber,qty,shippingdate,target_qty,warehouse
+P1000;100.10;90.20;95.30;kg;111.11;122.22;133.33
+EOL
+$entries = test_import($file, $settings1);
+$entry = $entries->[0];
+is scalar @{ $entry->{errors} }, 3, "Three errors occurred";
+
+cmp_deeply(\@{ $entry->{errors} }, [
+                                    'Error: Warehouse not found',
+                                    'Error: Bin not found',
+                                    'Error: Part not found'
+                                   ],
+          "Errors for bullshit import are ok"
+);
+
+##### create minor bullshit
+$file = \<<EOL;
+warehouse,bin,partnumber,qty,chargenumber,comment,employee_id,qty,shippingdate,target_qty
+Warehouse,"Bin 1","ap 1",3.4
+EOL
+
+$entries = test_import($file, $settings1);
+$entry = $entries->[0];
+is scalar @{ $entry->{errors} }, 1, "One error for minor bullshit occurred";
+
+cmp_deeply(\@{ $entry->{errors} }, [
+                                    'Error: A quantity and a target quantity could not be given both.'
+                                   ],
+          "Error for minor bullshit import are ok"
+);
+
+
+##### add some qty on earth, but we have something already stocked
+set_stock(
+  part => $part1,
+  qty => 25,
+  bin => $bin1,
+);
+
+is(SL::Helper::Inventory::get_stock(part => $part1), "25.00000", 'simple get_stock works');
+is(SL::Helper::Inventory::get_onhand(part => $part1), "25.00000", 'simple get_onhand works');
+
+my ($trans_id, $inv_obj, $tt);
+# add some stuff
+
+$file = \<<EOL;
+warehouse,bin,partnumber,qty,chargenumber,comment,employee_id,shippingdate
+Warehouse,"Bin 1","ap 1",3.4
+EOL
+$entries = test_import($file, $settings1);
+$entry = $entries->[0];
+is scalar @{ $entry->{errors} }, 0, "No error for valid data occurred";
+is $entry->{object}->qty, "3.4", "Valid qty accepted";  # evals to text
+is(SL::Helper::Inventory::get_stock(part => $part1),  "28.40000",  'simple add (stock) qty works');
+is(SL::Helper::Inventory::get_onhand(part => $part1), "28.40000", 'simple add (onhand) qty works');
+
+# now check the real Inventory entry
+$trans_id = $entry->{object}->trans_id;
+$inv_obj = SL::DB::Manager::Inventory->find_by(trans_id => $trans_id);
+
+# we expect one entry for one trans_id
+is ref $inv_obj, "SL::DB::Inventory",             "One inventory object, no array or undef";
+is $inv_obj->qty == 3.4, 1,                       "Valid qty accepted";  # evals to text
+is $inv_obj->comment, 'Lager Inventur Standard',  "Valid comment accepted";  # evals to text
+is $inv_obj->employee_id, 1,                      "Employee valid";  # evals to text
+is ref $inv_obj->shippingdate, 'DateTime',        "Valid DateTime for shippingdate";
+is $inv_obj->shippingdate, DateTime->today_local, "Default shippingdate set";
+
+$tt = SL::DB::Manager::TransferType->find_by(id => $inv_obj->trans_type_id);
+
+is ref $tt, 'SL::DB::TransferType',       "Valid TransferType, no undef";
+is $tt->direction, 'in',                  "Transfer direction correct";
+is $tt->description, 'correction',        "Transfer description correct";
+
+# remove some stuff
+
+$file = \<<EOL;
+warehouse,bin,partnumber,qty,chargenumber,comment,employee_id,shippingdate
+Warehouse,"Bin 1","ap 1",-13.4
+EOL
+$entries = test_import($file, $settings1);
+$entry = $entries->[0];
+is scalar @{ $entry->{errors} }, 0, "No error for valid data occurred";
+is $entry->{object}->qty, "-13.4", "Valid qty accepted";  # evals to text
+is(SL::Helper::Inventory::get_stock(part => $part1),  "15.00000",  'simple add (stock) qty works');
+is(SL::Helper::Inventory::get_onhand(part => $part1), "15.00000", 'simple add (onhand) qty works');
+
+# now check the real Inventory entry
+$trans_id = $entry->{object}->trans_id;
+$inv_obj = SL::DB::Manager::Inventory->find_by(trans_id => $trans_id);
+
+# we expect one entry for one trans_id
+is ref $inv_obj, "SL::DB::Inventory",             "One inventory object, no array or undef";
+is $inv_obj->qty == -13.4, 1,                       "Valid qty accepted";  # evals to text
+is $inv_obj->comment, 'Lager Inventur Standard',  "Valid comment accepted";  # evals to text
+is $inv_obj->employee_id, 1,                      "Employee valid";  # evals to text
+is ref $inv_obj->shippingdate, 'DateTime',        "Valid DateTime for shippingdate";
+is $inv_obj->shippingdate, DateTime->today_local, "Default shippingdate set";
+
+$tt = SL::DB::Manager::TransferType->find_by(id => $inv_obj->trans_type_id);
+
+is ref $tt, 'SL::DB::TransferType',       "Valid TransferType, no undef";
+is $tt->direction, 'out',                  "Transfer direction correct";
+is $tt->description, 'correction',        "Transfer description correct";
+
+# repeat both test cases but with target qty instead of qty (should throw an error for neg. case)
+# and customise comment
+# add some stuff
+
+$file = \<<EOL;
+warehouse,bin,partnumber,target_qty,comment
+Warehouse,"Bin 1","ap 1",3.4,"Alter, wir haben uns voll verhauen bei der aktuellen Zielmenge!"
+EOL
+$entries = test_import($file, $settings1);
+$entry = $entries->[0];
+is scalar @{ $entry->{errors} }, 0, "No error for valid data occurred";
+is $entry->{object}->qty, "-11.6", "Valid qty accepted";  # evals to text qty = target_qty - actual_qty
+is(SL::Helper::Inventory::get_stock(part => $part1),  "3.40000",  'simple add (stock) qty works');
+is(SL::Helper::Inventory::get_onhand(part => $part1), "3.40000", 'simple add (onhand) qty works');
+
+# now check the real Inventory entry
+$trans_id = $entry->{object}->trans_id;
+$inv_obj = SL::DB::Manager::Inventory->find_by(trans_id => $trans_id);
+
+# we expect one entry for one trans_id
+is ref $inv_obj, "SL::DB::Inventory",             "One inventory object, no array or undef";
+is $inv_obj->qty == -11.6, 1,                       "Valid qty accepted";
+is $inv_obj->comment,
+  "Alter, wir haben uns voll verhauen bei der aktuellen Zielmenge!",  "Valid comment accepted";
+is $inv_obj->employee_id, 1,                      "Employee valid";
+is ref $inv_obj->shippingdate, 'DateTime',        "Valid DateTime for shippingdate";
+is $inv_obj->shippingdate, DateTime->today_local, "Default shippingdate set";
+
+$tt = SL::DB::Manager::TransferType->find_by(id => $inv_obj->trans_type_id);
+
+is ref $tt, 'SL::DB::TransferType',       "Valid TransferType, no undef";
+is $tt->direction, 'out',                  "Transfer direction correct";
+is $tt->description, 'correction',        "Transfer description correct";
+
+# remove some stuff, but too much
+
+$file = \<<EOL;
+warehouse,bin,partnumber,target_qty,comment
+Warehouse,"Bin 1","ap 1",-13.4,"Jetzt stimmt aber alles"
+EOL
+$entries = test_import($file, $settings1);
+$entry = $entries->[0];
+is scalar @{ $entry->{errors} }, 1, "One error for invalid data occurred";
+is $entry->{object}->qty, undef, "No data accepted";  # evals to text
+is(SL::Helper::Inventory::get_stock(part => $part1),  "3.40000",  'simple add (stock) qty works');
+is(SL::Helper::Inventory::get_onhand(part => $part1), "3.40000", 'simple add (onhand) qty works');
+
+# now check the real Inventory entry
+$trans_id = $entry->{object}->trans_id;
+$inv_obj = SL::DB::Manager::Inventory->find_by(trans_id => $trans_id);
+
+is ref $trans_id, '',         "No trans_id -> undef";
+is ref $inv_obj,  '',         "No inventory object -> undef";
+
+# add some stuff, but realistic value
+
+$file = \<<EOL;
+warehouse,bin,partnumber,target_qty,comment
+Warehouse,"Bin 1","ap 1",33.75,"Jetzt wirklich"
+EOL
+$entries = test_import($file, $settings1);
+$entry = $entries->[0];
+is scalar @{ $entry->{errors} }, 0, "No error for valid data occurred";
+is $entry->{object}->qty, "30.35", "Valid qty accepted";  # evals to text qty = target_qty - actual_qty
+is(SL::Helper::Inventory::get_stock(part => $part1),  "33.75000",  'simple add (stock) qty works');
+is(SL::Helper::Inventory::get_onhand(part => $part1), "33.75000", 'simple add (onhand) qty works');
+
+# now check the real Inventory entry
+$trans_id = $entry->{object}->trans_id;
+$inv_obj = SL::DB::Manager::Inventory->find_by(trans_id => $trans_id);
+
+# we expect one entry for one trans_id
+is ref $inv_obj, "SL::DB::Inventory",             "One inventory object, no array or undef";
+is $inv_obj->qty == 30.35, 1,                     "Valid qty accepted";
+is $inv_obj->comment, "Jetzt wirklich",           "Valid comment accepted";
+is $inv_obj->employee_id, 1,                      "Employee valid";
+is ref $inv_obj->shippingdate, 'DateTime',        "Valid DateTime for shippingdate";
+is $inv_obj->shippingdate, DateTime->today_local, "Default shippingdate set";
+
+$tt = SL::DB::Manager::TransferType->find_by(id => $inv_obj->trans_type_id);
+
+is ref $tt, 'SL::DB::TransferType',       "Valid TransferType, no undef";
+is $tt->direction, 'in',                  "Transfer direction correct";
+is $tt->description, 'correction',        "Transfer description correct";
+
+# target_qty is 0
+
+$file = \<<EOL;
+warehouse,bin,partnumber,target_qty,comment
+Warehouse,"Bin 1","ap 1",0,"Jetzt wirklich"
+EOL
+$entries = test_import($file, $settings1);
+$entry = $entries->[0];
+is scalar @{ $entry->{errors} }, 0, "No error for valid data occurred";
+is $entry->{object}->qty, "-33.75", "Valid qty accepted";  # evals to text qty = target_qty - actual_qty
+is(SL::Helper::Inventory::get_stock(part => $part1),  "0.00000",  'simple add (stock) qty works');
+is(SL::Helper::Inventory::get_onhand(part => $part1), undef, 'simple add (onhand) qty works'); # hmm good return?
+
+# now check the real Inventory entry
+$trans_id = $entry->{object}->trans_id;
+$inv_obj = SL::DB::Manager::Inventory->find_by(trans_id => $trans_id);
+
+# we expect one entry for one trans_id
+is ref $inv_obj, "SL::DB::Inventory",             "One inventory object, no array or undef";
+is $inv_obj->qty == -33.75000, 1,                       "Valid qty accepted";
+is $inv_obj->comment,
+  "Jetzt wirklich",  "Valid comment accepted";
+is $inv_obj->employee_id, 1,                      "Employee valid";
+is ref $inv_obj->shippingdate, 'DateTime',        "Valid DateTime for shippingdate";
+is $inv_obj->shippingdate, DateTime->today_local, "Default shippingdate set";
+
+$tt = SL::DB::Manager::TransferType->find_by(id => $inv_obj->trans_type_id);
+
+is ref $tt, 'SL::DB::TransferType',       "Valid TransferType, no undef";
+is $tt->direction, 'out',                  "Transfer direction correct";
+is $tt->description, 'correction',        "Transfer description correct";
+
+# add some stuff with a different numberformat
+
+$::myconfig{numberformat} = '1.000,00';
+$file = \<<EOL;
+warehouse,bin,partnumber,target_qty,comment
+Warehouse,"Bin 1","ap 1","31,2","Jetzt wirklich"
+EOL
+$entries = test_import($file, $settings1);
+$entry = $entries->[0];
+is scalar @{ $entry->{errors} }, 0, "No error for valid data occurred";
+is $entry->{object}->qty, "31.2",  "Valid qty accepted";  # evals to text qty = target_qty - actual_qty
+is(SL::Helper::Inventory::get_stock(part => $part1),  "31.20000",  'simple add (stock) qty works');
+is(SL::Helper::Inventory::get_onhand(part => $part1), "31.20000", 'simple add (onhand) qty works');
+
+# now check the real Inventory entry
+$trans_id = $entry->{object}->trans_id;
+$inv_obj = SL::DB::Manager::Inventory->find_by(trans_id => $trans_id);
+
+# we expect one entry for one trans_id
+is ref $inv_obj, "SL::DB::Inventory",             "One inventory object, no array or undef";
+is $inv_obj->qty == 31.2, 1,                     "Valid qty calculated";
+
+
+
+clear_up(); # remove all data at end of tests
+
+# end of tests
+
+done_testing();
+
+sub clear_up {
+  SL::DB::Manager::Inventory->delete_all(all => 1);
+  SL::DB::Manager::Assembly->delete_all(all => 1);
+  SL::DB::Manager::Part->delete_all(all => 1);
+  SL::DB::Manager::Bin->delete_all(all => 1);
+  SL::DB::Manager::Warehouse->delete_all(all => 1);
+}
+
+sub create_standard_stock {
+  ($wh, $bin1)          = create_warehouse_and_bins();
+  ($wh_moon, $bin_moon) = create_warehouse_and_bins(
+      warehouse_description => 'Our warehouse location at the moon',
+      bin_description       => 'Lunar crater',
+    );
+  $bin2 = SL::DB::Bin->new(description => "Bin 2", warehouse => $wh)->save;
+  $wh->load;
+
+  $assembly1  =  new_assembly(number_of_parts => 2)->save;
+  ($part1, $part2) = map { $_->part } $assembly1->assemblies;
+
+  $service1 = new_service(partnumber  => "service number 1",
+                          description => "We really need this service",
+                         )->save;
+  my $assembly_items;
+  push( @{$assembly_items}, SL::DB::Assembly->new(parts_id => $part1->id,
+                                                  qty      => 12,
+                                                  position => 1,
+                                                  ));
+  push( @{$assembly_items}, SL::DB::Assembly->new(parts_id => $part2->id,
+                                                  qty      => 6.34,
+                                                  position => 2,
+                                                  ));
+  push( @{$assembly_items}, SL::DB::Assembly->new(parts_id => $service1->id,
+                                                  qty      => 1.2,
+                                                  position => 3,
+                                                  ));
+  $assembly_service  =  new_assembly(description    => 'Ein Erzeugnis mit Dienstleistungen',
+                                     assembly_items => $assembly_items
+                                    )->save;
+}
+
+
+
+
+1;
diff --git a/t/db/delivery_order.t b/t/db/delivery_order.t
new file mode 100644 (file)
index 0000000..372cc87
--- /dev/null
@@ -0,0 +1,49 @@
+use Test::More;
+
+use strict;
+
+use lib 't';
+use utf8;
+
+use Carp;
+use Data::Dumper;
+use Support::TestSetup;
+use Test::Exception;
+
+use SL::DB::Order;
+use SL::DB::Customer;
+use SL::DB::Department;
+use SL::DB::Currency;
+use SL::DB::PaymentTerm;
+use SL::DB::DeliveryTerm;
+use SL::DB::Employee;
+use SL::DB::Part;
+use SL::DB::Unit;
+use SL::DB::DeliveryOrder;
+use SL::DB::DeliveryOrder::TypeData qw(:types);
+
+use SL::Dev::ALL qw(:ALL);
+
+Support::TestSetup::login();
+
+
+#######
+
+my $order1 = SL::Dev::Record::create_purchase_order(
+  save                    => 1,
+  taxincluded             => 0,
+);
+
+my $delivery_order = SL::DB::DeliveryOrder->new_from($order1);
+
+is $delivery_order->type, PURCHASE_DELIVERY_ORDER_TYPE, "new_from purchase order gives purchase delivery order";
+is scalar @{ $delivery_order->items }, 2, "purchase delivery order keeps items";
+is $delivery_order->vendor_id, $order1->vendor_id, "purchase delivery order keeps vendor";
+
+my $supplier_delivery_order = SL::DB::DeliveryOrder->new_from($order1, type => SUPPLIER_DELIVERY_ORDER_TYPE);
+
+is $supplier_delivery_order->type, SUPPLIER_DELIVERY_ORDER_TYPE, "new_from purchase order with given type gives supplier delivery order";
+is scalar @{ $supplier_delivery_order->items }, 0, "supplier delivery order ignores items";
+is $supplier_delivery_order->vendor_id, $order1->vendor_id, "supplier delivery order keeps vendor";
+
+done_testing();
index 8d08899..62adec4 100644 (file)
@@ -1,4 +1,4 @@
-use Test::More tests => 41;
+use Test::More tests => 75;
 
 use strict;
 
@@ -30,7 +30,7 @@ my ($transdate);
 my $VISUAL_TEST = 0;  # just a sleep to click around
 
 sub clear_up {
-  foreach (qw(DeliveryOrderItem DeliveryOrder InvoiceItem Invoice Part Customer Department PaymentTerm)) {
+  foreach (qw(DeliveryOrderItem DeliveryOrder OrderItem Order InvoiceItem Invoice Part Customer Department PaymentTerm)) {
     "SL::DB::Manager::${_}"->delete_all(all => 1);
   }
   SL::DB::Manager::Employee->delete_all(where => [ login => 'testuser' ]);
@@ -127,7 +127,8 @@ my $do1 = create_sales_delivery_order(
                     transdate       => '06.03.2015',
                     unit            => $unit->name,
                   )
-                ]
+                ],
+  transaction_description => 'Liefervorgang',
 );
 
 
@@ -149,7 +150,7 @@ is (SL::DB::Manager::DeliveryOrderItem->get_all_count(where => [ delivery_order_
 
 
 # convert this do to invoice
-my $invoice = $do1->convert_to_invoice(transdate => $transdate);
+my $invoice = $do1->convert_to_invoice(transdate => $transdate, attributes => {transaction_description => 'Rechnungsvorgang'});
 
 sleep (300) if $VISUAL_TEST; # we can do a real visual test via gui login
 # test invoice afterwards
@@ -165,6 +166,7 @@ is($invoice->payment_terms->description, "14Tage 2%Skonto, 30Tage netto", 'payme
 $invoice->load;
 
 is($invoice->cusordnumber            , 'b84da'           , 'cusordnumber check');
+is($invoice->transaction_description,  'Rechnungsvorgang', 'transaction description (changed on conversion) check');
 is($invoice->department->description , "Test Department" , 'department description ok');
 is($invoice->amount                  , '1354.20000'      , 'amount check');
 is($invoice->marge_percent           , '50.88666'        , 'marge percent check');
@@ -235,6 +237,114 @@ foreach ( $do1_item1->id, $do1_item2->id ) {
   is($links_record_item1[0]->{to_table}   , 'invoice'              , "record to table check $_");
 }
 
+##############
+# test conversion from order to invoice
+##############
+
+reset_state();
+
+# we create A16399 with two items
+my $o1 = create_sales_order(
+  save            => 1,
+  'department_id' => $department->id,
+  'transdate'     => $transdate,
+  'employee_id'   => $employee->id,
+  'intnotes'      => 'some intnotes',
+  'ordnumber'     => 'A16399',
+  'payment_id'    => $payment_do->id,
+  'salesman_id'   => $employee->id,
+  'shippingpoint' => 'sendtome',
+  'shipvia'       => 'DHL, Versand am 06.03.2015, 1 Paket  17,00 kg',
+  'cusordnumber'  => 'b84da',
+  'customer_id'   => $customer->id,
+  'notes'         => '<ul><li><strong>fett</strong></li><li><strong>und</strong></li><li><strong>mit</strong></li><li><strong>bullets</strong></li><li>&nbsp;</li></ul>',
+  orderitems => [
+                  create_order_item(
+                    part               => $parts[0],
+                    discount           => '0.25',
+                    lastcost           => '49.95000',
+                    longdescription    => "<ol><li>27</li><li>28</li><li>29</li><li><sub>asdf</sub></li><li><sub>asdf</sub></li><li><sup>oben</sup></li></ol><p><s>kommt nicht mehr vor</s></p>",
+                    marge_price_factor => 1,
+                    qty                => '2.00000',
+                    sellprice          => '242.20000',
+                    unit               => $unit->name,
+                  ),
+                  create_order_item(
+                    part            => $parts[1],
+                    discount        => '0.25',
+                    lastcost        => '153.00000',
+                    qty             => '3.00000',
+                    sellprice       => '344.30000',
+                    transdate       => '06.03.2015',
+                    unit            => $unit->name,
+                  )
+  ],
+  transaction_description => 'Auftragsvorgang',
+);
+
+
+# TESTS
+
+my $o1_item1 = $o1->orderitems->[0];
+my $o1_item2 = $o1->orderitems->[1];
+
+# convert this order to invoice
+$invoice = $o1->convert_to_invoice(transdate => $transdate, attributes => {transaction_description => 'Rechnungsvorgang'});
+$invoice->load;
+
+# test invoice afterwards
+ok ($invoice->shipvia eq "DHL, Versand am 06.03.2015, 1 Paket  17,00 kg", "convert form order: ship via check");
+ok ($invoice->shippingpoint eq "sendtome", "convert form order: shipping point check");
+ok ($invoice->ordnumber eq "A16399", "convert form order: ordnumber check");
+ok ($invoice->notes eq '<ul><li><strong>fett</strong></li><li><strong>und</strong></li><li><strong>mit</strong></li><li><strong>bullets</strong></li><li>&nbsp;</li></ul>', "convert form order: do RichText notes saved");
+ok(($o1->closed) , 'convert form order: Order is closed after conversion');
+is($invoice->payment_terms->description, "14Tage 2%Skonto, 30Tage netto", 'convert form order: payment term description check');
+
+is($invoice->cusordnumber,            'b84da',            'convert form order: cusordnumber check');
+is($invoice->transaction_description, 'Rechnungsvorgang', 'convert form order: transaction description (changed on conversion) check');
+is($invoice->department->description, "Test Department",  'convert form order: department description ok');
+is($invoice->amount,                  '1354.20000',       'convert form order: amount check');
+is($invoice->marge_percent,           '50.88666',         'convert form order: marge percent check');
+is($invoice->marge_total,             '579.08000',        'convert form order: marge total check');
+is($invoice->netamount,               '1137.98000',       'convert form order: netamount check');
+
+# some item checks
+is($invoice->items_sorted->[0]->parts_id,         $parts[0]->id , 'convert form order: invoiceitem 1 linked with part');
+is(scalar @{ $invoice->invoiceitems },            2,              'convert form order: two invoice items linked with invoice');
+is($invoice->items_sorted->[0]->position,         1,              "convert form order: position 1 order correct");
+is($invoice->items_sorted->[1]->position,         2,              "convert form order: position 2 order correct");
+is($invoice->items_sorted->[0]->part->partnumber, 'v-519160549' , "convert form order: partnumber 1 correct");
+is($invoice->items_sorted->[1]->part->partnumber, 'v-120160086' , "convert form order: partnumber 2 correct");
+is($invoice->items_sorted->[0]->qty,              '2.00000',      "convert form order: pos 1 qty");
+is($invoice->items_sorted->[1]->qty,              '3.00000',      "convert form order: pos 2 qty");
+is($invoice->items_sorted->[0]->discount,         0.25,           "convert form order: pos 1 discount");
+is($invoice->items_sorted->[1]->discount,         0.25,           "convert form order: pos 2 discount");
+is($invoice->items_sorted->[0]->longdescription , "<ol><li>27</li><li>28</li><li>29</li><li><sub>asdf</sub></li><li><sub>asdf</sub></li><li><sup>oben</sup></li></ol><p><s>kommt nicht mehr vor</s></p>",
+     "convert form order: invoice item1 rich text longdescripition");
+
+# check linked records AND linked items
+@links_record = RecordLinks->get_links('from_table' => 'oe',
+                                       'to_table'   => 'ar',
+                                       'from_id'    => $o1->id,
+);
+
+is($links_record[0]->{from_id},    $o1->id, "convert form order: record from id check");
+is($links_record[0]->{from_table}, 'oe',    "convert form order: record from table check");
+is($links_record[0]->{to_table},   'ar',    "convert form order: record to table check");
+
+my $i = 0;
+foreach ( $o1_item1->id, $o1_item2->id ) {
+  $i++;
+  my @links_record_item = RecordLinks->get_links('from_table' => 'orderitems',
+                                                  'to_table'   => 'invoice',
+                                                  'from_id'    => $_,
+                                                 );
+
+  is($links_record_item[0]->{from_id},    $_ ,          "convert form order: record from id check item $i");
+  is($links_record_item[0]->{from_table}, 'orderitems', "convert form order: record from table check item $i");
+  is($links_record_item[0]->{to_table},   'invoice',    "convert form order: record to table check item $i");
+}
+
 clear_up();
 
 1;
index 89610d6..154e48c 100644 (file)
@@ -14,6 +14,8 @@ use List::Util qw(sum);
 use SL::Dev::Record qw(create_invoice_item create_sales_invoice create_credit_note create_ap_transaction);
 use SL::Dev::CustomerVendor qw(new_customer new_vendor);
 use SL::Dev::Part qw(new_part);
+use SL::DB::BankTransaction;
+use SL::DB::BankTransactionAccTrans;
 use SL::DB::Buchungsgruppe;
 use SL::DB::Currency;
 use SL::DB::Exchangerate;
@@ -29,7 +31,8 @@ use SL::DB::PaymentTerm;
 use SL::DBUtils qw(selectfirst_array_query);
 use Data::Dumper;
 
-my ($customer, $vendor, $currency_id, @parts, $buchungsgruppe, $buchungsgruppe7, $unit, $employee, $tax, $tax7, $tax_9, $taxzone, $payment_terms, $bank_account);
+my ($customer, $vendor, $currency_id, @parts, $buchungsgruppe, $buchungsgruppe7, $unit, $employee, $tax, $tax7, $tax_9, $taxzone, $payment_terms,
+    $bank_account, $bt);
 my ($transdate1, $transdate2, $transdate3, $transdate4, $currency, $exchangerate, $exchangerate2, $exchangerate3, $exchangerate4);
 my ($ar_chart,$bank,$ar_amount_chart, $ap_chart, $ap_amount_chart, $fxloss_chart, $fxgain_chart);
 
@@ -50,13 +53,13 @@ test_default_ap_transaction_two_charts_19_7_tax_partial_unrounded_payment_withou
 test_default_invoice_one_item_19_without_skonto_overpaid();
 test_credit_note_two_items_19_7_tax_tax_not_included();
 
-# test cases: difference_as_skonto
-test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
-test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent();
-test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent();
-test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto();
-test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent();
-test_default_ap_transaction_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
+# test cases: free_skonto
+test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_free_skonto();
+test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_free_skonto_1cent();
+test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_free_skonto_2cent();
+test_default_invoice_one_item_19_multiple_payment_final_free_skonto();
+test_default_invoice_one_item_19_multiple_payment_final_free_skonto_1cent();
+test_default_ap_transaction_two_charts_19_7_tax_without_skonto_multiple_payments_final_free_skonto();
 
 # test cases: with_skonto_pt
 test_default_invoice_two_items_19_7_tax_with_skonto_50_50();
@@ -99,6 +102,8 @@ sub clear_up {
   SL::DB::Manager::Part->delete_all(all => 1);
   SL::DB::Manager::Customer->delete_all(all => 1);
   SL::DB::Manager::Vendor->delete_all(all => 1);
+  SL::DB::Manager::BankTransactionAccTrans->delete_all(all => 1);
+  SL::DB::Manager::BankTransaction->delete_all(all => 1);
   SL::DB::Manager::BankAccount->delete_all(all => 1);
   SL::DB::Manager::PaymentTerm->delete_all(all => 1);
   SL::DB::Manager::Exchangerate->delete_all(all => 1);
@@ -237,6 +242,17 @@ sub init_state {
   $bank            = SL::DB::Manager::Chart->find_by( accno => '1200' ); # Bank
   $ar_amount_chart = SL::DB::Manager::Chart->find_by( accno => '8400' ); # Erlöse
   $ap_amount_chart = SL::DB::Manager::Chart->find_by( accno => '3400' ); # Wareneingang 19%
+
+  $bt = SL::DB::BankTransaction->new(
+    local_bank_account_id => $bank_account->id,
+    transdate             => $transdate1,
+    valutadate            => $transdate1,
+    amount                => 27332.32,
+    purpose               => 'dummy',
+    currency              => $currency,
+  );
+  $bt->save || die $@;
+
 }
 
 sub new_ap_transaction {
@@ -273,7 +289,7 @@ sub number_of_payments {
   my $paid_amount;
   foreach my $transaction ( @{ $invoice->transactions } ) {
     if ( $transaction->chart_link =~ /(AR_paid|AP_paid)/ ) {
-      $paid_amount += $transaction->amount ;
+      $paid_amount += $transaction->amount;
       $number_of_payments++;
     }
   };
@@ -378,8 +394,9 @@ sub test_default_invoice_two_items_19_7_tax_with_skonto {
   );
 
   # default values
-  my %params = ( chart_id => $bank_account->chart_id,
+  my %params = ( chart_id  => $bank_account->chart_id,
                  transdate => $transdate1,
+                 bt_id     => $bt->id,
                );
 
   $params{payment_type} = 'with_skonto_pt';
@@ -411,8 +428,9 @@ sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included {
   );
 
   # default values
-  my %params = ( chart_id => $bank_account->chart_id,
+  my %params = ( chart_id  => $bank_account->chart_id,
                  transdate => $transdate1,
+                 bt_id     => $bt->id,
                );
 
   $params{payment_type} = 'with_skonto_pt';
@@ -535,7 +553,7 @@ sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments {
 }
 
 # test 6
-sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto {
+sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_free_skonto {
   my $title = 'default invoice, two items, 19/7% tax not included';
 
   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
@@ -557,15 +575,21 @@ sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_fin
                          chart_id     => $bank_account->chart_id,
                          transdate    => $transdate1,
                        );
-  $invoice->pay_invoice( amount       => $invoice->open_amount,
-                         payment_type => 'difference_as_skonto',
-                         chart_id     => $bank_account->chart_id,
-                         transdate    => $transdate1,
+  # free_skonto does:
+  #  my $open_amount = $payment_type eq 'with_skonto_pt' ? $invoice->amount_less_skonto : $invoice->open_amount;
+  #  $open_amount    = abs($open_amount);
+  #  $open_amount   -= $free_skonto_amount if ($payment_type eq 'free_skonto');
+
+  $invoice->pay_invoice( skonto_amount => $invoice->open_amount,
+                         amount        => 0,
+                         payment_type  => 'free_skonto',
+                         chart_id      => $bank_account->chart_id,
+                         transdate     => $transdate1,
+                         bt_id         => $bt->id,
                        );
 
   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
   my $total = total_amount($invoice);
-
   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
   is($paid_amount,                     -19.44,     "${title}: paid amount");
@@ -575,13 +599,15 @@ sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_fin
 
 }
 
-sub  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent {
+sub  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_free_skonto_1cent {
   my $title = 'default invoice, two items, 19/7% tax not included';
 
   # if there is only one cent left there can only be one skonto booking, the
   # error handling should choose the highest amount, which is the 7% account
   # (11.66) rather than the 19% account (5.85).  The actual tax amount is
   # higher for the 19% case, though (1.11 compared to 0.82)
+  #
+  # -> wrong: sub name. two cents are still left. one cent for each tax case. no tax correction
 
   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
@@ -597,12 +623,13 @@ sub  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_fi
                          chart_id     => $bank_account->chart_id,
                          transdate    => $transdate1,
                        );
-  $invoice->pay_invoice( amount       => $invoice->open_amount,
-                         payment_type => 'difference_as_skonto',
+  $invoice->pay_invoice( skonto_amount => $invoice->open_amount,
+                         amount       => 0,
+                         payment_type => 'free_skonto',
                          chart_id     => $bank_account->chart_id,
                          transdate    => $transdate1,
+                         bt_id        => $bt->id,
                        );
-
   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
   my $total = total_amount($invoice);
 
@@ -610,12 +637,11 @@ sub  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_fi
   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
   is($paid_amount,                     -19.44,     "${title}: paid amount");
   is($invoice->paid,                    19.44,     "${title}: paid");
-  is($number_of_payments,                   3,     "${title}: 2 AR_paid bookings");
+  is($number_of_payments,                   3,     "${title}: 3 AR_paid bookings");
   is($total,                                0,     "${title}: even balance");
-
 }
 
-sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent {
+sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_free_skonto_2cent {
   my $title = 'default invoice, two items, 19/7% tax not included';
 
   # if there are two cents left there will be two skonto bookings, 1 cent each
@@ -633,10 +659,12 @@ sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_fin
                          chart_id     => $bank_account->chart_id,
                          transdate    => $transdate1,
                        );
-  $invoice->pay_invoice( amount       => $invoice->open_amount,
-                         payment_type => 'difference_as_skonto',
+  $invoice->pay_invoice( skonto_amount => $invoice->open_amount,
+                         amount       => 0,
+                         payment_type => 'free_skonto',
                          chart_id     => $bank_account->chart_id,
                          transdate    => $transdate1,
+                         bt_id        => $bt->id,
                        );
 
   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
@@ -651,7 +679,7 @@ sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_fin
 
 }
 
-sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto {
+sub test_default_invoice_one_item_19_multiple_payment_final_free_skonto {
   my $title = 'default invoice, one item, 19% tax, without_skonto';
 
   my $item    = create_invoice_item(part => $parts[0], qty => 2.5);
@@ -665,6 +693,7 @@ sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto
   # default values
   my %params = ( chart_id  => $bank_account->chart_id,
                  transdate => $transdate1,
+                 bt_id     => $bt->id,
                );
 
   $params{amount}       = '2.32';
@@ -675,8 +704,9 @@ sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto
   $params{payment_type} = 'without_skonto';
   $invoice->pay_invoice( %params );
 
-  $params{amount}       = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
-  $params{payment_type} = 'difference_as_skonto';
+  $params{skonto_amount} = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
+  $params{amount}        = 0,
+  $params{payment_type}  = 'free_skonto';
   $invoice->pay_invoice( %params );
 
   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
@@ -691,7 +721,7 @@ sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto
 
 }
 
-sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent {
+sub test_default_invoice_one_item_19_multiple_payment_final_free_skonto_1cent {
   my $title = 'default invoice, one item, 19% tax, without_skonto';
 
   my $item    = create_invoice_item(part => $parts[0], qty => 2.5);
@@ -705,14 +735,16 @@ sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto
   # default values
   my %params = ( chart_id  => $bank_account->chart_id,
                  transdate => $transdate1,
+                 bt_id     => $bt->id,
                );
 
   $params{amount}       = '6.95';
   $params{payment_type} = 'without_skonto';
   $invoice->pay_invoice( %params );
 
-  $params{amount}       = $invoice->open_amount; # set amount, otherwise previous value 6.95 is used
-  $params{payment_type} = 'difference_as_skonto';
+  $params{skonto_amount} = $invoice->open_amount;
+  $params{amount}        = 0,
+  $params{payment_type} = 'free_skonto';
   $invoice->pay_invoice( %params );
 
   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
@@ -756,14 +788,16 @@ sub test_default_ap_transaction_two_charts_19_7_with_skonto {
 
   my $ap_transaction = new_ap_transaction();
 
-  my %params = ( chart_id => $bank_account->chart_id,
+  my %params = ( chart_id  => $bank_account->chart_id,
                  transdate => $transdate1,
+                 bt_id     => $bt->id,
                );
-
-  # $params{amount} = '226'; # pass full amount
+  # BankTransaction-Controller __always__ calcs amount:
+  # my $open_amount = $payment_type eq 'with_skonto_pt' ? $invoice->amount_less_skonto : $invoice->open_amount;
+  $ap_transaction->payment_terms($ap_transaction->vendor->payment);
+  $params{amount}       = $ap_transaction->amount_less_skonto; # pass calculated skonto amount
   $params{payment_type} = 'with_skonto_pt';
 
-  $ap_transaction->payment_terms($ap_transaction->vendor->payment);
   $ap_transaction->pay_invoice( %params );
 
   my ($number_of_payments, $paid_amount) = number_of_payments($ap_transaction);
@@ -795,8 +829,8 @@ sub test_default_ap_transaction_two_charts_19_7_tax_partial_unrounded_payment_wi
 };
 
 
-sub test_default_ap_transaction_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto {
-  my $title = 'default ap_transaction, two charts, 19/7% tax multiple payments with final difference as skonto';
+sub test_default_ap_transaction_two_charts_19_7_tax_without_skonto_multiple_payments_final_free_skonto {
+  my $title = 'default ap_transaction, two charts, 19/7% tax multiple payments with final free skonto';
 
   my $ap_transaction = new_ap_transaction();
 
@@ -814,16 +848,19 @@ sub test_default_ap_transaction_two_charts_19_7_tax_without_skonto_multiple_paym
                           transdate    => $transdate1,
                          );
   $ap_transaction->pay_invoice(
-                          payment_type => 'difference_as_skonto',
+                          payment_type => 'free_skonto',
+                          skonto_amount => $ap_transaction->open_amount,
+                          amount       => 0,
                           chart_id     => $bank_account->chart_id,
                           transdate    => $transdate1,
+                          bt_id        => $bt->id,
                          );
 
   my ($number_of_payments, $paid_amount) = number_of_payments($ap_transaction);
   my $total = total_amount($ap_transaction);
 
   is($paid_amount,         226, "${title}: paid amount");
-  is($number_of_payments,    4, "${title}: 1 AP_paid bookings");
+  is($number_of_payments,    4, "${title}: 4 AP_paid bookings");
   is($total,                 0, "${title}: even balance");
 
 }
@@ -844,6 +881,7 @@ sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50 {
   # default values
   my %params = ( chart_id => $bank_account->chart_id,
                  transdate => $transdate1,
+                 bt_id     => $bt->id,
                );
 
   $params{amount} = $invoice->amount_less_skonto;
@@ -880,6 +918,7 @@ sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25 {
   # default values
   my %params = ( chart_id => $bank_account->chart_id,
                  transdate => $transdate1,
+                 bt_id     => $bt->id,
                );
 
   $params{amount} = $invoice->amount_less_skonto;
@@ -915,6 +954,7 @@ sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included {
   # default values
   my %params = ( chart_id => $bank_account->chart_id,
                  transdate => $transdate1,
+                 bt_id     => $bt->id,
                );
 
   $params{amount} = $invoice->amount_less_skonto;
@@ -955,9 +995,12 @@ sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple {
                          chart_id     => $bank_account->chart_id,
                          transdate => $transdate1,
                        );
-  $invoice->pay_invoice( payment_type => 'difference_as_skonto',
+  $invoice->pay_invoice( payment_type => 'free_skonto',
                          chart_id     => $bank_account->chart_id,
                          transdate    => $transdate1,
+                         bt_id        => $bt->id,
+                         skonto_amount => $invoice->open_amount,
+                         amount        => 0,
                        );
 
   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
index 0c46af9..2c7ea4d 100644 (file)
@@ -19,6 +19,7 @@ use SL::DB::Employee;
 use SL::DB::Invoice;
 use SL::DB::Order;
 use SL::DB::DeliveryOrder;
+use SL::DB::DeliveryOrder::TypeData qw(:types);
 use SL::DB::Part;
 use SL::DB::Unit;
 use SL::DB::TaxZone;
@@ -86,6 +87,7 @@ sub new_delivery_order {
     employee_id => $employee->id,
     salesman_id => $employee->id,
     taxzone_id  => $taxzone->id,
+    order_type => SALES_DELIVERY_ORDER_TYPE,
     %params,
   )->save;
 }
index 0afff35..91934de 100644 (file)
@@ -18,7 +18,7 @@ Support::TestSetup::login();
 my $dbh = SL::DB->client->dbh;
 my @charts = qw(379000 136900 372000 372500 373000 374000 377000 494700);
 local $::locale = Locale->new('en');
-diag("init csv");
+note("init csv");
 clear_up();
 
 # datev naming convention and expected filename entry in $::form
@@ -50,6 +50,23 @@ foreach my $accno (@charts) {
 }
 
 # and add department (KOST1 description)
+  SL::DB::Department->new(
+    description => 'Total falsche Abteilung, niemals zuordnen!'
+  )->save;
+
+  SL::DB::Department->new(
+    description => '2. Total falsche Abteilung, niemals zuordnen!'
+  )->save;
+
+  SL::DB::Department->new(
+    description => '3. Total falsche Abteilung, niemals zuordnen!'
+  )->save;
+
+  SL::DB::Department->new(
+    description => 'annahme stelle. Total falsche Abteilung, niemals zuordnen!'
+  )->save;
+
+
   SL::DB::Department->new(
     description => 'Wisavis'
   )->save;
@@ -73,7 +90,14 @@ foreach my $booking (@{ $gl_bookings }) {
 
   # gl
   is ($current_row->[13], $booking->reference, "Buchungstext correct");
-  is ("Wisavis", $booking->department->description, "Department correctly assigned");
+  if ($current_row->[36] eq 'wisavis') {
+    is(ref $booking->department eq 'SL::DB::Department', 1, "Department assigned");
+    is ($current_row->[36], 'wisavis', "Department correctly assigned");                # lowercase
+    is ('Wisavis', $booking->department->description, "Department correctly assigned"); # upper case
+  } else {
+    is ($current_row->[36], '', "No Department correctly assigned");
+
+  }
   is ($source, $booking->transactions->[0]->source, "Source 0 correctly assigned");
   is ($source, $booking->transactions->[1]->source, "Source 1 correctly assigned");
 
index adaca91..4b8b13d 100755 (executable)
--- a/t/run.sh
+++ b/t/run.sh
@@ -2,4 +2,6 @@
 
 dir="$(dirname "$0")"
 
-perl "-I${dir}/../modules/override" "-I${dir}/.." "-I${dir}/../modules/fallback" "$@"
+for TEST in "$@"; do
+  perl "-I${dir}/../modules/override" "-I${dir}/.." "-I${dir}/../modules/fallback" "$TEST"
+done
index e2861da..88638bb 100644 (file)
@@ -9,6 +9,8 @@ use utf8;
 use Support::TestSetup;
 use Test::Exception;
 
+use SL::DB::BankTransaction;
+use SL::DB::BankTransactionAccTrans;
 use SL::DB::Customer;
 use SL::DB::Vendor;
 use SL::DB::Invoice;
@@ -32,6 +34,9 @@ clear_up();
 #  neue Konten für 5% anlegen
 #  Leistungszeitraum vs. Datum Zuord. Steuerperiodest
 
+
+
+
 note('checking if all tax entries exist for Konjunkturprogramm');
 
 # create dates to test on
@@ -40,6 +45,30 @@ my $date_2020_1 = DateTime->new(year => 2020, month => 6, day => 15);
 my $date_2020_2 = DateTime->new(year => 2020, month => 7, day => 15);
 my $date_2021   = DateTime->new(year => 2021, month => 1, day => 15);
 
+# dummy bt_id
+my $bank_account     =  SL::DB::BankAccount->new(
+    account_number  => '123',
+    bank_code       => '123',
+    iban            => '123',
+    bic             => '123',
+    bank            => '123',
+    chart_id        => SL::DB::Manager::Chart->find_by( description => 'Bank' )->id,
+    name            => SL::DB::Manager::Chart->find_by( description => 'Bank' )->description,
+  )->save;
+
+
+my $currency_id     = $::instance_conf->get_currency_id;
+my  $bt = SL::DB::BankTransaction->new(
+    local_bank_account_id => $bank_account->id,
+    transdate             => $date_2021,
+    valutadate            => $date_2021,
+    amount                => 27332.32,
+    purpose               => 'dummy',
+    currency              => $currency_id,
+  );
+  $bt->save || die $@;
+
+
 # The only way to discern the pre-2007 16% tax from the 2020 16% tax is by
 # their configured automatic tax charts, so look them up here:
 
@@ -403,6 +432,7 @@ note('testing payments with skonto');
 
 my %params = ( chart_id     => $chart_bank->id,
                payment_type => 'with_skonto_pt',
+               bt_id        => $bt->id,
              );
 
 $sales_invoice_2020_2->pay_invoice( %params,
@@ -585,6 +615,9 @@ sub datev_test {
 }
 
 sub clear_up {
+  SL::DB::Manager::BankTransactionAccTrans->delete_all(all => 1);
+  SL::DB::Manager::BankTransaction->delete_all(all => 1);
+  SL::DB::Manager::BankAccount->delete_all(all => 1);
   SL::DB::Manager::OrderItem->delete_all(all => 1);
   SL::DB::Manager::Order->delete_all(all => 1);
   SL::DB::Manager::InvoiceItem->delete_all(all => 1);
index 8a272bd..3e75424 100644 (file)
@@ -1,21 +1,20 @@
-
 # Bemerkungen zum Vorlagensatz
-### © 2020 by Marei Peischl (peiTeX TeXnical Solutions)
+### © 2020–2021 by Marei Peischl (peiTeX TeXnical Solutions)
 
 ## Quickstart (wo kann was angepasst werden?):
 
   * insettings.tex : Pfad zu Angaben über Mandanten (default: firma)
                      Logo/Briefpapier
                      Layout der Kopf/Fußzeile
-                    innerhalb dieser Datei werden auch die folgenden Dateien geladen:
-                        firma/ident.tex        : Angaben über Mandanten
-                        firma/<währungskürzel>_account.tex
+                     innerhalb dieser Datei werden auch die folgenden Dateien geladen:
+                     firma/ident.tex        : Angaben über Mandanten
+                     firma/<währungskürzel>_account.tex
 
 * Es muß mindestens eine Sprache angelegt werden!
   -  deutsch.tex    : Textschnipsel für Deutsch
-                     Dafür eine Sprache mit Vorlagenkürzel DE anlegen
+                      Dafür eine Sprache mit Vorlagenkürzel DE anlegen
   -  english.tex    : Textschnipsel für Englisch
-                     Dafür eine Sprache mit Vorlagenkürzel EN anlegen
+                      Dafür eine Sprache mit Vorlagenkürzel EN anlegen
 
 
 
@@ -24,7 +23,7 @@ Die Grundstruktur besteht je Dokumententyp aus einer Basisdatei und verschiedene
 
 Die Basis wurde so überarbeitet, dass Dokumente nun generell auf der Dokumentenklasse *scrartcl.cls* basieren und das Paket *kiviletter.sty* benutzen.
 
-Mandantenspezifische Konfiguration findet sich in der Datei *insettings.tex* und dem Ordner eines spezifischen Mandanten (default=*firma/*). 
+Mandantenspezifische Konfiguration findet sich in der Datei *insettings.tex* und dem Ordner eines spezifischen Mandanten (default=*firma/*).
 
 
 ### Struktur der Basisdatei (je Dokumententyp eine)
@@ -36,7 +35,7 @@ Mandantenspezifische Konfiguration findet sich in der Datei *insettings.tex* und
    - Sprache: lädt die entsprechende Sprachdatei, falls DE -> *deutsch.tex*, falls EN *englisch.tex* und setzt die babel Optionen. Die Datei enthält Übersetzungen von Einzelbegriffen und Textbausteinen.
    - Lädt die Konfigurationsdatei, ohne spezielle Mandanten ist der Suchpfad zur Konfiguration der Unterordner *firma/*
    - Lädt die Datei *ident.tex*, sowie die Abbildung Briefkopf.
-               
+
 #### Mandanten / Firma:
 
 Um gleiche Vorlagen für verschiedene Firmen verwenden zu können, wird je
@@ -62,7 +61,15 @@ So kann in den Dokumenten je nach Währung ein anderes Konto
 angegeben werden.
 Nach demselben Schema können auch weitere, alternative Bankverbindungen
 angelegt werden, die dann in *insettings.tex* als Variable in der Fußzeile eingefügt werden.
-    
+Als Fallback (falls kivitendo keine Währung an das Druckvorlagen-System übergibt)
+ist Euro eingestellt. Dies lässt sich in der *insettings.tex* über das optionale Argument
+von `\setupCurrencyConfig` anpassen, z.B.
+
+```
+\setupCurrencyConfig[chf]{\identpath}{\lxcurrency}
+```
+für Schweizer Franken als Standardwährung.
+
 #### Briefbogen/Logos:
 Eine Hintergrundgrafik oder ein Logo kann in Abhängigkeit vom
 Medium (z.B. nur beim Verschicken mit E-Mail) eingebunden
@@ -71,8 +78,14 @@ werden.
 Desweiteren sind (auskommentierte) Beispiele enthalten für eine
 Grafik als Briefkopf, nur ein Logo, oder ein komplettes DinA4-PDF
 als Briefpapier.
-    
-#### Fusszeile:
+
+Absolute Positionierung innerhalb des Brief-Layouts ist über die entsprechende Dokumentation des scrlayer-Paketes möglich.
+Da die Voreinstellungen bereits einige Sonderfälle automatisch berücksichtigen ist mit den Anpassungen Vorsicht geboten.
+Sämtliche Einstellungen sollten jedoch außerhalb der *.sty-Dateien vorgenommen werden.
+Anpassungen der insettings.tex betreffen hierbei alle Mandanten. Mandantenspezifische Einstellung sind über die zugehörige Konfigurationsdatei möglich.
+In diesem Fall kann zum Ende der insettings eine weitere Konfigurationsdatei über die Verwendung von \identpath geladen werden. Ein Beispiel ist in der insettings.tex enthalten.
+
+#### Fußzeile:
 Die Tabelle im Fuß verwendet die Angaben aus *firma/ident.tex* und
 *firma/*_account.tex*. Ihre Struktur wird in der *insettings.tex* definiert.
 
@@ -80,7 +93,7 @@ Die Tabelle im Fuß verwendet die Angaben aus *firma/ident.tex* und
 Das Seitenlayout wird über scrlayer-scrpage bestimmt. Es existieren in der Datei *insettings.tex* einige Hinweise zu den Anpassungen. Die Basiskonfiguration ist ebenfalls dort eingetragen.
 
 Die Kopfzeile unterscheidet sich von Dokumententyp zu Dokumententyp leicht, da diese über Datenbankvariablen befüllt wird. Hierfür wird das Makro `\ourhead` definiert. Diese Definition kann ebenfalls über die *insettings.tex* geändert werden.
-        
+
 ### Tabellen:
 
 Die Tabellenstruktur wurde komplett überarbeitet. Der Vorlagensatz verfügt über Tabellen, die automatisch die Breite der Textbreite anpassen und zusätzlich Seitenumbrüche erlauben.
@@ -136,19 +149,47 @@ Die Spaltenbreite der Spalte `desc` für die Artikelbeschreibung nimmt dabei jew
 ##### Kopfzeileneinträge
 
 Die Kopfzeileneinträge werden über die Option `<Spaltenname>/header=<Neue Beschriftung>` angepasst.
-Vorbelegt ist die Konfiguration: 
+Vorbelegt ist die Konfiguration:
 
 ```
 \SetupPricingTabular{
-       pos/header=\position,
-       id/header=\artikelnummer,
-       desc/header=\bezeichnung,
-       amount/header=\menge,
-       price/header=\einzelpreis,
-       pricetotal/header=\gesamtpreis
+  pos/header=\position,
+  id/header=\artikelnummer,
+  desc/header=\bezeichnung,
+  amount/header=\menge,
+  price/header=\einzelpreis,
+  pricetotal/header=\gesamtpreis
 }
 ```
 
+##### Farbige Tabellen
+Versionen ab Juli 2021 enthalten die Möglichkeit farbige Tabellen zu nutzen.
+Die Optionen für die `PricingTabular` Umgebung können wie folgt konfiguriert werden:
+```
+  color-rows=<true/false>,% false
+  rowcolor-odd=<Farbname>,% black!10
+  rowcolor-even=<Farbname>,% leer, also keine Farbbox wird erzeugt
+  rowcolor-header=<Farbname>,% black!35
+  rowcolor-total=<Farbname>,% black!35
+```
+Die Angabe hinter dem Kommentarzeichen entspricht der Voreinstellung.
+
+#### Trennlinien zwischen den Einträgen
+Die Umgebung `PricingTabular` hat die möglichkeit horizontale Linien zwischen den Einträgen der `\FakeTable` einzuziehen.
+Die einfachste Möglichkeit hierfür ist die Option hrule, sie setzt automatisch eine Linie der Dicke `\lightrulewidth`.
+Da diese Linie formal nicht innerhalb der Tabelle platziert wird, können Linienmakros für Tabellen heir nicht verwendet werden.
+Falls dennoch eine manuelle Anpassung der Maße notwendig ist, kann direkt der Code zur Erzeugung der Linie übergeben werden.
+Die Option `hrule` entspricht der Angabe
+```
+  rowsep={
+    \vskip\aboverulesep
+    \hrule\@height\lightrulewidth
+    \vskip\belowrulesep
+  }
+```
+Es wird somit auch der Abstand davor und danach mit eingefügt. In Kombination mit Farbigen Tabellen ist hier vorsicht geboten, da der Abstand nicht mit zur farbigen Box gerechnet wird.
+
+
 ##### Reihenfolge/Anzahl der Spalten ändern
 
 Die Reihenfolge wurde über die Option `columns` festgelegt.
index 69a4e8a..7907ebe 100644 (file)
 \setkomavar{title}{\lagerliste}
 
 \setkomavar{firsthead}{
-       \normalsize
-       \noindent\begin{tabular}[t]{@{}l@{}}
-               <%company%>\strut\\
-               <%address%>
-       \end{tabular}
-       \hfill
- \begin{tabular}[t]{rr@{}}
-               Tel & <%tel%>\\
-               Fax & <%fax%>%
-       \end{tabular}
-       \rule{\linewidth}{\heavyrulewidth}
+  \normalsize
+  \noindent\begin{tabular}[t]{@{}l@{}}
+    <%company%>\strut\\
+    <%address%>
+  \end{tabular}
+  \hfill
 \begin{tabular}[t]{rr@{}}
+    Tel & < %tel%>\\
+    Fax & < %fax%>%
+  \end{tabular}
+  \rule{\linewidth}{\heavyrulewidth}
 }
 
 \makeatletter
 \setkomavar{location}{
-               \backaddr@format{\scriptsize\usekomafont{backaddress}%
-                       \strut\lieferanschrift
-               }
-               \par\medskip\setlength{\parskip}{\z@}
-               \normalsize
-               <%shiptoname%>\par
-               <%if shiptocontact%> <%shiptocontact%><%end if%>\par
-               <%shiptodepartment_1%>\par
-               <%shiptodepartment_2%>\par
-               <%shiptostreet%>\par
-               <%shiptozipcode%> <%shiptocity%>%
-       }
+  \backaddr@format{\scriptsize\usekomafont{backaddress}%
+    \strut\lieferanschrift
+  }
+  \par\medskip\setlength{\parskip}{\z@}
+  \normalsize
+  <%shiptoname%>\par
+  <%if shiptocontact%> <%shiptocontact%><%end if%>\par
+  <%shiptodepartment_1%>\par
+  <%shiptodepartment_2%>\par
+  <%shiptostreet%>\par
+  <%shiptozipcode%> <%shiptocity%>%
+}
 \makeatother
 
 \begin{letter}{
-               <%name%>\ifhmode\\\fi
-               <%street%>\ifhmode\\\fi
-               <%zipcode%> <%city%>\ifhmode\\\fi
-               <%country%>
-       }
+<%name%>\ifhmode\\\fi
+<%street%>\ifhmode\\\fi
+<%zipcode%> <%city%>\ifhmode\\\fi
+<%country%>
+}
 
 \opening{}
 
 \begin{SimpleTabular}[colspec=*6X,headline={\bfseries\bestellnummer&\bfseries\datum&\bfseries\kontakt
-  <%if warehouse%>%
-  &\bfseries\lager%
-  <%end warehouse%>%
-  &\bfseries\lagerplatz&\bfseries\lieferungMit}]
+        <%if warehouse%>%
+        &\bfseries\lager%
+        <%end warehouse%>%
+        &\bfseries\lagerplatz&\bfseries\lieferungMit}]
 
   <%ordnumber%>%
   &%
   <%if shippingdate%>%
-       <%shippingdate%>%
+  <%shippingdate%>%
   <%end shippingdate%>%
   <%if not shippingdate%>%
-       <%orddate%>%
+  <%orddate%>%
   <%end shippingdate%>%
   & <%employee%>%
   <%if warehouse%>%
 \bigskip
 
 \begin{SimpleTabular}[colspec=rlXllrrll,headline={\bfseries\position&\bfseries\nummer&\bfseries\beschreibung&\bfseries\seriennummer & &\bfseries\menge&\bfseries\erh&&\bfseries\lagerplatz}]
-<%foreach number%>%
+  <%foreach number%>%
   <%runningnumber%> & <%number%> & <%description%> & <%serialnumber%> &
   <%deliverydate%> & <%qty%> & <%ship%> & <%unit%> & <%bin%> \\
-<%end number%>%
+  <%end number%>%
 \end{SimpleTabular}
 
 \end{letter}
index 2725140..ad428f7 100644 (file)
 \setplength{firstheadvpos}{4cm}
 
 \setkomavar{firsthead}{
-       \noindent\begin{tabular}[t]{@{}l@{}}
-               <%company%>\strut\\
-               <%address%>
-       \end{tabular}
-       \hfill
-       <%source%>\par
-       \medskip
-       <%text\_amount%> \dotfill <%decimal%>/100 \par\smallskip
-       \hfill <%datepaid%> \hspace{2cm}\strut<%amount%>
+  \noindent\begin{tabular}[t]{@{}l@{}}
+    <%company%>\strut\\
+    <%address%>
+  \end{tabular}
+  \hfill
+  <%source%>\par
+  \medskip
+  <%text\_amount%> \dotfill <%decimal%>/100 \par\smallskip
+  \hfill <%datepaid%> \hspace{2cm}\strut<%amount%>
 }
 
 
 \begin{document}
 
 \begin{letter}{
-               <%name%>\ifhmode\\\fi
-               <%street%>\ifhmode\\\fi
-               <%zipcode%> <%city%>\ifhmode\\\fi
-               <%country%>%
-       }
+<%name%>\ifhmode\\\fi
+<%street%>\ifhmode\\\fi
+<%zipcode%> <%city%>\ifhmode\\\fi
+<%country%>%
+}
 
 \opening{<%company%>}
 \pagestyle{empty}
@@ -43,9 +43,9 @@
 <%name%> \hfill <%datepaid%> \hfill <%source%>%
 
 \begin{SimpleTabular}[colspec=lXrr,headline={\bfseries\rechnung&\bfseries\ausgestellt&\bfseries\faellig&\bfseries\verrechnet}]
-<%foreach invnumber%>%
-<%invnumber%> & <%invdate%> & <%due%> & <%paid%> \\
-<%end invnumber%>%
+  <%foreach invnumber%>%
+  <%invnumber%> & <%invdate%> & <%due%> & <%paid%> \\
+  <%end invnumber%>%
 \end{SimpleTabular}
 
 \end{letter}
index 8c05c10..b764c1d 100644 (file)
 \ourhead{\kundennummer}{<%customernumber%>}{\gutschrift}{<%invnumber%>}{<%invdate%>}
 
 \setkomavar*{date}{\datum}
-\setkomavar{date}{<%transdate%>}       
+\setkomavar{date}{<%invdate%>}
 \setkomavar{customer}{<%customernumber%>}
 \setkomavar{fromname}{<%employee_name%>}
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \gutschrift~
-       \nr ~<%invnumber%>%
+  \gutschrift~
+  \nr ~<%invnumber%>%
 }
 
 <%if invnumber_for_credit_note%>%
-       \setkomavar*{myref}{\fuerRechnung}
-       \setkomavar{myref}{<%invnumber_for_credit_note%>}
+  \setkomavar*{myref}{\fuerRechnung}
+  \setkomavar{myref}{<%invnumber_for_credit_note%>}
 <%end if%>%
 
-
-
+\setkomavar{transaction}{<%transaction_description%>}
 <%if shiptoname%>%
 \makeatletter
 \begin{lrbox}\shippingAddressBox
-       \parbox{\useplength{toaddrwidth}}{
-               \backaddr@format{\scriptsize\usekomafont{backaddress}%
-                       \strut\abweichendeLieferadresse
-               }
-               \par\smallskip
-               \setlength{\parskip}{\z@}
-               \par
-               \normalsize
-               <%shiptoname%>\par
-               <%if shiptocontact%> <%shiptocontact%><%end if%>\par
-               <%shiptodepartment_1%>\par
-               <%shiptodepartment_2%>\par
-               <%shiptostreet%>\par
-               <%shiptozipcode%> <%shiptocity%>%
-       }
+  \parbox{\useplength{toaddrwidth}}{
+    \backaddr@format{\scriptsize\usekomafont{backaddress}%
+      \strut\abweichendeLieferadresse
+    }
+    \par\smallskip
+    \setlength{\parskip}{\z@}
+    \par
+    \normalsize
+    <%shiptoname%>\par
+    <%if shiptocontact%> <%shiptocontact%><%end if%>\par
+    <%shiptodepartment_1%>\par
+    <%shiptodepartment_2%>\par
+    <%shiptostreet%>\par
+    <%shiptozipcode%> <%shiptocity%>%
+  }
 \end{lrbox}
 \makeatother
 <%end if%>%
 \begin{document}
 
 \begin{letter}{
-               <%name%>\strut\\
-               <%if department_1%><%department_1%>\\<%end if%>%
-               <%if department_2%><%department_2%>\\<%end if%>%
-               <%cp_givenname%> <%cp_name%>\strut\\
-               <%street%>\strut\\
-               <%zipcode%> <%city%>\strut\\
-               <%country%> \strut
-       }
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
+}
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-               {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-               {
-                       \Ifstr{<%cp_gender%>}{f}
-                               {\anredefrau}
-                               {\anredeherr}
-                               <%cp_title%> <%cp_name%>,
-               }
-       }
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
 \thispagestyle{kivitendo.letter.first}
 
 
 \gutschriftformel
 
-\begin{PricingTabular*}%
-% eigentliche Tabelle%
-\FakeTable{%
-       <%foreach number%>%
-               <%runningnumber%> &%
-               <%number%> &%
-               \textbf{<%description%>}%
-               <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
-               <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
-               <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
-               <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
-               &%
-               <%qty%> <%unit%> &%
-               <%sellprice%>&%
-               \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
-               <%linetotal%>\tabularnewline%
-       <%end number%>%
-       }%
-       \begin{PricingTotal}%
-               % Tabellenende letzte Seite
-               \nettobetrag & <%subtotal%>\\%
-               <%foreach tax%>%
-               <%taxdescription%> & <%tax%>\\%
-               <%end tax%>%
-               \bfseries\schlussbetrag &  \bfseries <%ordtotal%>\\%
-       \end{PricingTotal}%
-\end{PricingTabular*}
-
 <%if notes%>%
 <%notes%>%
-\medskip
+\vspace{0.5cm}
 <%end if%>%
 
+
+\begin{PricingTabular*}%
+  % eigentliche Tabelle%
+  \FakeTable{%
+  <%foreach number%>%
+  <%runningnumber%> &%
+  <%number%> &%
+  \textbf{<%description%>}%
+  <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
+  <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
+  <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
+  <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
+  &%
+  <%qty%> <%unit%> &%
+  <%sellprice%>&%
+  \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
+    <%linetotal%>\tabularnewline%
+    <%end number%>%
+  }%
+  \begin{PricingTotal}%
+    % Tabellenende letzte Seite
+    \nettobetrag & <%subtotal%>\\%
+    <%foreach tax%>%
+    <%taxdescription%> & <%tax%>\\%
+    <%end tax%>%
+    \bfseries\schlussbetrag &  \bfseries <%invtotal%>\\%
+  \end{PricingTotal}%
+\end{PricingTabular*}
+
+
 \closing{\gruesse}
 
 \end{letter}
index bf24eeb..47eafa1 100644 (file)
@@ -49,7 +49,7 @@
 \newcommand{\angebot} {Angebot}
 \newcommand{\angebotsformel} {gerne unterbreiten wir Ihnen folgendes Angebot:}
 \newcommand{\angebotdanke} {Wir danken für Ihre Anfrage und hoffen, Ihnen hiermit ein interessantes Angebot gemacht zu haben.}
-\newcommand{\angebotgueltig} {Das Angebot ist freibleibend gültig bis zum}            %Danach wird das Datum eingefügt, falls das grammatisch nicht funktionieren sollte müssen wir eine ausnahme für die sprache definieren
+\newcommand{\angebotgueltig} {Das Angebot ist freibleibend gültig bis zum}Danach wird das Datum eingefügt, falls das grammatisch nicht funktionieren sollte müssen wir eine ausnahme für die sprache definieren
 \newcommand{\angebotfragen} {Sollten Sie noch Fragen oder Änderungswünsche haben, können Sie uns gerne jederzeit unter den unten genannten Telefonnummern oder E-Mail-Adressen kontaktieren.}
 \newcommand{\angebotagb} {Bei der Durchführung des Auftrags gelten unsere AGB, die wir Ihnen gerne zuschicken.}
 \newcommand{\auftragerteilt}{Auftrag erteilt:}
 
 % rechnung (invoice)
 \newcommand{\rechnung} {Rechnung}
+\newcommand{\rechnungskopie} {Rechnungskopie}
 \newcommand{\rechnungsdatum} {Rechnungsdatum}
 \newcommand{\ihrebestellung} {Ihre Bestellung}
 \newcommand{\lieferdatum} {Lieferdatum}
 \newcommand{\rechnungsformel} {für unsere Leistungen erlauben wir uns, folgende Positionen in Rechnung zu stellen:}
 \newcommand{\zwischensumme} {Zwischensumme}
 \newcommand{\leistungsdatumGleichRechnungsdatum} {Das Leistungsdatum entspricht, soweit nicht anders angegeben, dem Rechnungsdatum.}
+\newcommand{\leistungsdatum} {Leistungsdatum}
 \newcommand{\unserebankverbindung} {Unsere Bankverbindung}
 \newcommand{\textKontonummer} {Kontonummer:}
 \newcommand{\textBank} {bei der}
 
 \newcommand{\textUstid} {UStId:}
 
+% anzahlungsrechnung (invoice_for_advance_payment)
+\newcommand{\anzahlungsrechnung} {Anzahlungsrechnung}
+\newcommand{\schlussrechnung} {Schlussrechnung}
+\newcommand{\ust} {USt}
+\newcommand{\abzueglichAnzahlungsrechnungen} {Abzüglich folgender Anzahlungsrechnungen}
+\newcommand{\rechnungsbetrag} {Rechnungsbetrag}
+
 % gutschrift (credit_note)
 \newcommand{\gutschrift} {Gutschrift}
 \newcommand{\fuerRechnung} {für Rechnung}
 
 % einkaufslieferschein (purchase_delivery_order)
 \newcommand{\einkaufslieferschein} {Eingangslieferschein}
+\newcommand{\beistelllieferschein} {Beistell-Lieferschein}
 
 % Brief/letter
 \newcommand{\ihrzeichen}{Ihr Zeichen}
 
 %sammelliste
 \newcommand*{\sammelliste}{Sammelliste}
-\newcommand*{\lagerausgang}{Lagerausgang}
\ No newline at end of file
+\newcommand*{\lagerausgang}{Lagerausgang}
index 13f2a9e..f757c78 100644 (file)
@@ -48,7 +48,7 @@
 \newcommand{\angebot} {Quotation}
 \newcommand{\angebotsformel} {we are pleased to make the following offer:}
 \newcommand{\angebotdanke} {We thank you for your request and look forward to receiving your order.}
-\newcommand{\angebotgueltig} {This offer is valid until}               %Danach wird das Datum eingefügt, falls das grammatisch nicht funktionieren sollte müssen wir eine ausnahme für die sprache definieren
+\newcommand{\angebotgueltig} {This offer is valid until}% Danach wird das Datum eingefügt, falls das grammatisch nicht funktionieren sollte müssen wir eine Ausnahme für die Sprache definieren
 \newcommand{\angebotfragen} {If you have any questions do not hesitate to conatct us.}
 \newcommand{\angebotagb} {Our general terms and conditions (AGB) apply. We will send them to you on request.}
 \newcommand{\auftragerteilt}{Order confirmed:}
 
 % rechnung (invoice)
 \newcommand{\rechnung} {Invoice}
+\newcommand{\rechnungskopie} {Invoice copy}
 \newcommand{\rechnungsdatum} {Invoice date}
 \newcommand{\ihrebestellung} {Your order}
 \newcommand{\lieferdatum} {Delivery date}
 \newcommand{\rechnungsformel} {we invoice you for the following items:}
 \newcommand{\zwischensumme} {Subtotal}
 \newcommand{\leistungsdatumGleichRechnungsdatum} {The date of service corresponds to that of the invoice.}
+\newcommand{\leistungsdatum} {Service Date}
 \newcommand{\unserebankverbindung} {Our bank details}
 \newcommand{\textKontonummer} {Account no.:}
 \newcommand{\textBank} {at}
 
 \newcommand{\textUstid} {VAT number:}
 
+% anzahlungsrechnung (invoice_for_advance_payment)
+\newcommand{\anzahlungsrechnung} {Invoice for advance payment}
+\newcommand{\schlussrechnung} {Final Invoice}
+\newcommand{\ust} {VAT}
+\newcommand{\abzueglichAnzahlungsrechnungen} {Minus following invoices for advance payment}
+\newcommand{\rechnungsbetrag} {Invoice amount}
+
 % gutschrift (credit_note)
 \newcommand{\gutschrift} {Credit note}
 \newcommand{\fuerRechnung} {for invoice}
 
 % einkaufslieferschein (purchase_delivery_order)
 \newcommand{\einkaufslieferschein} {Purchase delivery order}
+\newcommand{\beistelllieferschein} {Supplier Delivery Order}
 
 % Brief/letter
 \newcommand{\ihrzeichen}{Your reference}
diff --git a/templates/print/marei/final_invoice.tex b/templates/print/marei/final_invoice.tex
new file mode 120000 (symlink)
index 0000000..b6a6ad8
--- /dev/null
@@ -0,0 +1 @@
+invoice.tex
\ No newline at end of file
index 00c78b7..80e08d5 100644 (file)
@@ -2,5 +2,5 @@
 \newcommand{\kontonummer}{4004 283 800}
 \newcommand{\bank}{GLS Bank eG}
 \newcommand{\bankleitzahl}{430 609 67}
-\newcommand{\bic}{DE87430609674004283800}
-\newcommand{\iban}{GENODEM1GLS}
+\newcommand{\iban}{DE50430609674071953800}
+\newcommand{\bic}{GENODEM1GLS}
diff --git a/templates/print/marei/firma/default_account.tex b/templates/print/marei/firma/default_account.tex
deleted file mode 100644 (file)
index e436c3d..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-\newcommand{\kontonummer}{4071953800}
-\newcommand{\bank}{GLS Bank eG}
-\newcommand{\bankleitzahl}{430 609 67}
-\newcommand{\bic}{DE50430609674071953800}
-\newcommand{\iban}{GENODEM1GLS}
-%Keine Definition von \currency!
index 4963272..2cecb8e 100644 (file)
@@ -2,5 +2,5 @@
 \newcommand{\kontonummer}{4071953800}
 \newcommand{\bank}{GLS Bank eG}
 \newcommand{\bankleitzahl}{430 609 67}
-\newcommand{\bic}{DE50430609674071953800}
-\newcommand{\iban}{GENODEM1GLS}
+\newcommand{\iban}{DE50430609674071953800}
+\newcommand{\bic}{GENODEM1GLS}
index b2dd261..6539b11 100644 (file)
@@ -23,7 +23,7 @@ in einen anderen EU-Mitgliedstaat (Gelangensbestätigung)
 \vspace{0.4cm}
 
 {\color{purple} Bitte unterschreiben und faxen/mailen an:
-  \begin{center} <%employee_fax%> / <%employee_email%> \end{center}}
+\begin{center} <%employee_fax%> / <%employee_email%> \end{center}}
 \normalsize
 \vspace{0.4cm}
 <%name%>, <%street%>, <%zipcode%> <%city%>, <%country%>\hspace*{\fill}\\
@@ -45,7 +45,7 @@ innergemeinschaftlichen Lieferung\\
 im\\
 
 \uline{ \StrGobbleLeft{<%reqdate%>}{3} \hspace*{\fill}}\\
-{\color{gray}(Monat und Jahr des Erhalts des Liefergegenstands im Mitgliedstaat, in den der Liefergegenstand gelangt ist, wenn der liefernde Unternehmer den Liefergegenstand befördert oder versendet hat oder wenn der Abnehmer den Liefergegenstand versendet hat)}\\
+  {\color{gray}(Monat und Jahr des Erhalts des Liefergegenstands im Mitgliedstaat, in den der Liefergegenstand gelangt ist, wenn der liefernde Unternehmer den Liefergegenstand befördert oder versendet hat oder wenn der Abnehmer den Liefergegenstand versendet hat)}\\
 
 
 \TextField[name=delivery, bordercolor=gray, width=\linewidth]{}\\
@@ -55,7 +55,7 @@ in / nach \textsuperscript{1)}\\
 
 
 \uline{<%country%>\hspace*{\fill}}\\
-{\color{gray}(Mitgliedstaat und Ort, wohin der Liefergegenstand im Rahmen einer Beförderung oder Versendung gelangt ist)}\\
+  {\color{gray}(Mitgliedstaat und Ort, wohin der Liefergegenstand im Rahmen einer Beförderung oder Versendung gelangt ist)}\\
 
 erhalten habe / gelangt ist.
 
index 6bda090..5f9516c 100644 (file)
@@ -23,7 +23,7 @@ Certification of the entry of the object of an intra-Community supply into anoth
 \vspace{0.4cm}
 
 {\color{purple} Please sign below and send back to fax-number/mail-address:
-  \begin{center} <%employee_fax%> / <%employee_email%> \end{center}}
+\begin{center} <%employee_fax%> / <%employee_email%> \end{center}}
 
 \normalsize
 \vspace{0.4cm}
@@ -44,7 +44,7 @@ I as the customer hereby certify my receipt / the entry \textsuperscript{1)} of
 in\\
 
 \uline{ \StrGobbleLeft{<%reqdate%>}{3} \hspace*{\fill}}\\
-{\color{gray}(Month and year the object of the supply was received in the Member State of entry if the supplying trader transported or dispatched the object of the supply or if the customer dispatched the object of the supply)}\\
+  {\color{gray}(Month and year the object of the supply was received in the Member State of entry if the supplying trader transported or dispatched the object of the supply or if the customer dispatched the object of the supply)}\\
 
 \TextField[name=delivery, bordercolor=gray, width=\linewidth]{}\\
 {\color{gray}(Month and year the transportation ended if the customer transported the object of the supply himself or herself)}\\
@@ -52,7 +52,7 @@ in\\
 in / at \textsuperscript{1)}\\
 
 \uline{<%country%>\hspace*{\fill}}\\
-{\color{gray}(Member State and place of entry as part of the transport or dispatch of the object)}\\
+  {\color{gray}(Member State and place of entry as part of the transport or dispatch of the object)}\\
 
 
 % X\TextField[name=delivery, bordercolor=gray, width=\linewidth]{}\\
index 5cfc860..4174909 100644 (file)
@@ -1,16 +1,16 @@
 %% insettings.tex
-%% Copyright 2019 Marei Peischl
-\ProvidesFile{insettings.tex}[2019/12/22 Konfigurationsdatei kivitendo ERP]
+%% Copyright 2019–2022 Marei Peischl
+\ProvidesFile{insettings.tex}[2022/02/23 Konfigurationsdatei kivitendo ERP]
 % Sprachüberprüfung
 \RequirePackage[english, ngerman]{babel}
 
 \makeatletter
 \Ifstr{\lxlangcode}{EN}{
-       \main@language{english}
-       \input{english.tex}}{
-       \Ifstr{\lxlangcode}{DE}{
-               \main@language{ngerman}
-               \input{deutsch.tex}}{\input{deutsch.tex}}
+  \main@language{english}
+  \input{english.tex}}{
+  \Ifstr{\lxlangcode}{DE}{
+    \main@language{ngerman}
+    \input{deutsch.tex}}{\input{deutsch.tex}}
 } % Ende EN
 
 % Mandanten-/Firmenabhängigkeiten
@@ -23,7 +23,7 @@
 
 %Ganzseitiger Briefbogen als Hintergrund:
 %\DeclareNewLayer[page,background,
-%      contents={\includegraphics{Briefbogen}} %Hier muss der Dateinamen und ggf. die Bildgröße angepasst werden, falls es abweichende Maße vom Papierformat hat.
+%  contents={\includegraphics{Briefbogen}} %Hier muss der Dateinamen und ggf. die Bildgröße angepasst werden, falls es abweichende Maße vom Papierformat hat.
 %]{background}
 %\AddLayersToPageStyle{kivitendo.letter.first}{background}%Hintergrund für die erste Seite aktivieren
 %\AddLayersToPageStyle{kivitendo.letter}{background}% Hintergrund für die übrigen Briefseiten aktivieren.
 
 % Währungen/Konten
 % Die Konfiguration bedindet sich in der Datei 
-% \identpath/<euro/chf/usd/default>_account.tex
+% \identpath/<euro/chf/usd>_account.tex
+% das optionale Argument ist als euro vorbelegt und gibt die Einstellung an, falls \lxcurrency nicht von kivitendo übergeben wird.
 
-\@ifundefined{lxcurrency}{}{
-       \setupCurrencyConfig{\identpath}{\lxcurrency}
-}
+\setupCurrencyConfig[euro]{\identpath}{\lxcurrency}
 
 
 % Befehl f. normale Schriftart und -größe
 
 \KOMAoptions{
-       fontsize=10pt,
-       parskip=half-,% Absatzkennzeichnung durch Abstand statt Einzug
+  fontsize=10pt,
+  parskip=half-,% Absatzkennzeichnung durch Abstand statt Einzug
 }
 % Hier ist es auch möglich zusätzliche Schriftarten zu laden.
 % 
 % % \ifoot{<inhalt innen/links>}\cfoot{<inhalt zentriert>}\ofoot{<inhalt außen/rechts>}
 % dann sollte jedoch darauf geachtet werden, dass das Makro in den einzelnen Vorlagen aufgerufen wird und daher definiert sein sollte. 
 \newcommand{\ourhead}[5] {
-       \chead{
-         \makebox[\textwidth]{
-         \Ifstr{#1}{}{}{#1: #2 \hspace{0.7cm}}
-         #3
-         \Ifstr{#4}{}{}{~\nr: #4}
-         \Ifstr{#5}{}{}{\vom ~ #5}
-         \hspace{0.7cm} - \seite ~ \thepage/\letterlastpage  ~-%
-         }
-       }
+  \chead{
+    \makebox[\textwidth]{
+      \Ifstr{#1}{}{}{#1: #2 \hspace{0.7cm}}
+      #3
+      \Ifstr{#4}{}{}{~\nr: #4}
+      \Ifstr{#5}{}{}{\vom ~ #5}
+      \hspace{0.7cm} - \seite ~ \thepage/\letterlastpage  ~-%
+    }
+  }
 }
 
 %Ende Anpassungen der Kopfzeile
 %Box generieren, um die Höhe des Fußes zu kennen, damit ist eine automatische Anpassung des unteren Randes möglich
 \if@kivi@footer
 
-\newsavebox\footerbox
-\begin{lrbox}\footerbox
-       \usekomafont{pagefoot}%
-       % Anfang des eigentlichen Inhaltes der Fußzeile
-     \begin{tabular*}{\textwidth}[t]{@{\extracolsep{\fill}}p{.25\linewidth}p{.25\linewidth}r@{\extracolsep{0pt}\hspace{2\tabcolsep}}l@{}}%
-       \firma                 & \email              & \textKontonummer                  & \kontonummer \\
-       \strasse               & \homepage           & \textBank                         & \bank \\
-       \ort                   & \textUstid\ \ustid  & \textIban                         & \iban \\
-       \textTelefon~\telefon  & \finanzamt          & \textBic                          & \bic \\
-       \Ifstr{\fax}{}{}{\textFax~\fax} &                        &\textBankleitzahl                      & \bankleitzahl
-       \end{tabular*}
-       % Ende des Fußzeileninhaltes.
-\end{lrbox}
-
-%Box in den Fuß eintragen, durch die zusätzliche Angabe in der eckigen Klammer, wird die Fußzeile auch auf der ersten Seite verwendet, falls für die erste Seite eine unterschiedliche Fußzeile verwendet werden soll, ist es möglich den obigen Mechanismus mit einem anderen Makronamen als footerbox zu kopieren
-\cfoot[\usebox\footerbox]{\usebox\footerbox}
-
-%Fußhöhe auf Höhe der Box
-%Automatische Anpassung des unteren Randes
-\setlength{\footheight}{\dimexpr\ht\footerbox+\dp\footerbox}
-\setlength{\footskip}{\dimexpr\footheight+\baselineskip}
-\geometry{
-       includefoot,
-%      bottom=1cm,% Falls der untere Rand kleiner sein soll, als die Seitenränder.
-%      Weitere Anpassungen der Ränder sind hier ebenfalls möglich
-}
+  \newsavebox\footerbox
+  \begin{lrbox}\footerbox
+    \usekomafont{pagefoot}%
+    % Anfang des eigentlichen Inhaltes der Fußzeile
+    \begin{tabular*}{\textwidth}[t]{@{\extracolsep{\fill}}p{.25\linewidth}p{.25\linewidth}r@{\extracolsep{0pt}\hspace{2\tabcolsep}}l@{}}%
+      \firma                 & \email              & \textKontonummer       & \kontonummer \\
+      \strasse               & \homepage           & \textBank             & \bank \\
+      \ort                   & \textUstid\ \ustid  & \textIban             & \iban \\
+      \textTelefon~\telefon  & \finanzamt          & \textBic              & \bic \\
+      \Ifstr{\fax}{}{}{\textFax~\fax} &        &\textBankleitzahl       & \bankleitzahl
+    \end{tabular*}
+    % Ende des Fußzeileninhaltes.
+  \end{lrbox}
+
+  %Box in den Fuß eintragen, durch die zusätzliche Angabe in der eckigen Klammer, wird die Fußzeile auch auf der ersten Seite verwendet, falls für die erste Seite eine unterschiedliche Fußzeile verwendet werden soll, ist es möglich den obigen Mechanismus mit einem anderen Makronamen als footerbox zu kopieren
+  \cfoot[\usebox\footerbox]{\usebox\footerbox}
+
+  %Fußhöhe auf Höhe der Box
+  %Automatische Anpassung des unteren Randes
+  \setlength{\footheight}{\dimexpr\ht\footerbox+\dp\footerbox}
+  \setlength{\footskip}{\dimexpr\footheight+\baselineskip}
+  \geometry{
+    includefoot,
+    %  bottom=1cm,% Falls der untere Rand kleiner sein soll, als die Seitenränder.
+    %   Weitere Anpassungen der Ränder sind hier ebenfalls möglich
+  }
 
 \fi
 % Ende Anpassungen der Fußzeile
 
+%Mandantenspezifische ergänzende Einstellungen, falls nötig:
+%\InputIfFileExists{\identpath/dateiname}{}{}
+
 \makeatother
 \endinput
index 3e36ab1..b8970c2 100644 (file)
@@ -1,5 +1,15 @@
 \documentclass[paper=a4,fontsize=10pt]{scrartcl}
 \usepackage{kiviletter}
+<%if template_meta.formname == "invoice_copy"%>
+  \usepackage{transparent}
+  \DeclareNewLayer[page,foreground,contents={
+    \parbox[c][\layerheight][c]{\layerwidth}{\centering\color{gray}\scalebox{11}{\rotatebox{60}{\texttransparent{0.5}{\rechnungskopie}}}}
+  }]{foreground}
+  \AddLayersToPageStyle{kivitendo.letter.first}{foreground}%Hintergrund für die erste Seite aktivieren
+  \AddLayersToPageStyle{kivitendo.letter}{foreground}%Hintergrund für die erste Seite aktivieren
+<%end if%>
+
+
 
 
 % Variablen, die in settings verwendet werden
 % settings: Einstellungen, Logo, Briefpapier, Kopfzeile, Fusszeile
 \input{insettings.tex}
 
+<%if template_meta.formname == "invoice_for_advance_payment"%>
+  \renewcommand{\rechnung}{\anzahlungsrechnung}
+<%end if%>
+
+<%if template_meta.formname == "final_invoice"%>
+  \renewcommand{\rechnung}{\schlussrechnung}
+<%end if%>
 
 % laufende Kopfzeile:
 \ourhead{\kundennummer}{<%customernumber%>}{\rechnung}{<%invnumber%>}{<%invdate%>}
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \rechnung~ \nr ~<%invnumber%>%
+  \rechnung~ \nr ~<%invnumber%>%
 }
 <%if ordnumber%>%
-       \setkomavar*{myref}{\auftragsnummer}
-       \setkomavar{myref}{<%ordnumber%>}
+  \setkomavar*{myref}{\auftragsnummer}
+  \setkomavar{myref}{<%ordnumber%>}
+<%end if%>%
+<%if tax_point%>%
+  \setkomavar*{taxpoint}{\leistungsdatum}
+  \setkomavar{taxpoint}{<%tax_point%>}
 <%end if%>%
 <%if cusordnumber%>%
-       \setkomavar*{yourref}{\ihreBestellnummer}
-       \setkomavar{yourref}{<%cusordnumber%>}
+  \setkomavar*{yourref}{\ihreBestellnummer}
+  \setkomavar{yourref}{<%cusordnumber%>}
 <%end if%>%
 <%if donumber%>%
-       \setkomavar{delivery}{<%donumber%>}
+  \setkomavar{delivery}{<%donumber%>}
 <%end if%>%
 
 <%if quonumber%>%
 \setkomavar{quote}{<%quonumber%>}
 <%end if%>%
 
+\setkomavar{transaction}{<%transaction_description%>}
 <%if shiptoname%>%
 \makeatletter
 \begin{lrbox}\shippingAddressBox
-       \parbox{\useplength{toaddrwidth}}{
-               \backaddr@format{\scriptsize\usekomafont{backaddress}%
-                       \strut\abweichendeLieferadresse
-               }
-               \par\smallskip
-               \setlength{\parskip}{\z@}
-               \par
-               \normalsize
-               <%shiptoname%>\par
-               <%if shiptocontact%> <%shiptocontact%><%end if%>\par
-               <%shiptodepartment_1%>\par
-               <%shiptodepartment_2%>\par
-               <%shiptostreet%>\par
-               <%shiptozipcode%> <%shiptocity%>%
-       }
+  \parbox{\useplength{toaddrwidth}}{
+    \backaddr@format{\scriptsize\usekomafont{backaddress}%
+      \strut\abweichendeLieferadresse
+    }
+    \par\smallskip
+    \setlength{\parskip}{\z@}
+    \par
+    \normalsize
+    <%shiptoname%>\par
+    <%if shiptocontact%> <%shiptocontact%><%end if%>\par
+    <%shiptodepartment_1%>\par
+    <%shiptodepartment_2%>\par
+    <%shiptostreet%>\par
+    <%shiptozipcode%> <%shiptocity%>%
+  }
 \end{lrbox}
 \makeatother
 <%end if%>%
 \begin{document}
 
 \begin{letter}{
-               <%name%>\strut\\
-               <%if department_1%><%department_1%>\\<%end if%>%
-               <%if department_2%><%department_2%>\\<%end if%>%
-               <%cp_givenname%> <%cp_name%>\strut\\
-               <%street%>\strut\\
-               <%zipcode%> <%city%>\strut\\
-               <%country%> \strut
-       }
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
+}
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-               {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-               {
-                       \Ifstr{<%cp_gender%>}{f}
-                               {\anredefrau}
-                               {\anredeherr}
-                               <%cp_title%> <%cp_name%>,
-               }
-       }
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
 \thispagestyle{kivitendo.letter.first}
 
 <%if notes%>%
-        <%notes%>%
-        \vspace{0.5cm}
+<%notes%>%
+\vspace{0.5cm}
 <%end if%>%
 
 
 % Darüber hinaus kann die Reihenfolge verändert werden, die Voreinstellung entspricht:
 % \begin{PricingTabular*[columns={pos, id, desc, amount, price, pricetotal}]
 % Auf diese Art ist auch möglich mehrSpalten anzulegen als definiert sind. Für jede Spalte kann die Breite über weitere Optionen angepasst werden, die Einträge der columns-Liste entspricht den Spaltennamen.
-% 
+%
 % id = false, % deaktiviert die Spalte der Artikelnummer
 % amount = 1cm, % Setzt die Breite der Mengenspalte auf 1cm
 % desc/header = Artikelbeschreibung, %Ändert die Überschrift der Bezeichnunsspalte in „Artikelbeschreibung”
 \begin{PricingTabular*}%
-       % eigentliche Tabelle
-       \FakeTable{%
-       <%foreach number%>%
-               <%runningnumber%> &%
-               <%number%> &%
-               \textbf{<%description%>}%
-               <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
-               <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
-               <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
-               <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
-               &%
-               <%qty%> <%unit%> &%
-               <%sellprice%>&%
-               \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
-               <%linetotal%>\tabularnewline%
-       <%end number%>%
-       }%
-       \begin{PricingTotal}%
-               % Tabellenende letzte Seite
-               \nettobetrag & <%subtotal%>\\%
-               <%foreach tax%>%
-               <%taxdescription%> & <%tax%>\\%
-               <%end tax%>%
-               \bfseries\schlussbetrag &  \bfseries <%invtotal%>\\%
-       \end{PricingTotal}%
+  % eigentliche Tabelle
+  \FakeTable{%
+  <%foreach number%>%
+  <%runningnumber%> &%
+  <%number%> &%
+  \textbf{<%description%>}%
+  <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
+  <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
+  <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
+  <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
+  &%
+  <%qty%> <%unit%> &%
+  <%sellprice%>&%
+  \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
+    <%linetotal%>\tabularnewline%
+    <%end number%>%
+  }%
+  \begin{PricingTotal}%
+    % Tabellenende letzte Seite
+    \nettobetrag & <%subtotal%>\\%
+    <%foreach tax%>%
+    <%taxdescription%> & <%tax%>\\%
+    <%end tax%>%
+    \bfseries\schlussbetrag &  \bfseries <%invtotal%>\\%
+  \end{PricingTotal}%
 \end{PricingTabular*}
 
 \vspace{0.2cm}
 
-\Ifstr{<%deliverydate%>}{}{}{%
-       \leistungsdatumGleichRechnungsdatum%
+<%if template_meta.formname == "final_invoice"%>
+  <%if iap_existing%>
+    \abzueglichAnzahlungsrechnungen:\\
+    \begin{SimpleTabular}[colspec=llr<{\tabcurrency}r<{\tabcurrency},headline={\bfseries\nr& \bfseries\date& \bfseries\betrag & \bfseries\ust}]%
+      <%foreach iap_invnumber%>%
+        <%iap_invnumber%> & <%iap_transdate_as_date%> & <%iap_amount%> & <%iap_taxamount%>\\%
+      <%end iap_invnumber%>%
+    \end{SimpleTabular}%
+      \bfseries\rechnungsbetrag: <%iap_final_amount%> \currency\\%
+  <%end iap_available%>
+<%end%>%
+
+\Ifstr{<%deliverydate%>}{}{%
+  \leistungsdatumGleichRechnungsdatum%
 }{
-       \lieferungErfolgtAm ~<%deliverydate%>.
+  \lieferungErfolgtAm ~<%deliverydate%>.
 }\\
 
 <%if payment_terms%>%
-  \zahlung ~<%payment_terms%>\\
+\zahlung ~<%payment_terms%>\\
 <%end payment_terms%>%
 
 <%if delivery_term%>%
-  \lieferung ~<%delivery_term.description_long%>\\
+\lieferung ~<%delivery_term.description_long%>\\
 <%end delivery_term%>%
 
 <%if ustid%>\ihreustid ~<%ustid%>.\\<%end if%>%
 
 \ifnum<%taxzone_id%>=1
-    \steuerfreiEU\\  % EU mit USt-ID Nummer
+\steuerfreiEU\\  % EU mit USt-ID Nummer
 \else
-       \ifnum<%taxzone_id%>=3
-    \steuerfreiAUS\\  % Außerhalb EU
-    \fi
+\ifnum<%taxzone_id%>=3
+\steuerfreiAUS\\  % Außerhalb EU
+\fi
 \fi
 
 \closing{\gruesse}
diff --git a/templates/print/marei/invoice_copy.tex b/templates/print/marei/invoice_copy.tex
new file mode 120000 (symlink)
index 0000000..b6a6ad8
--- /dev/null
@@ -0,0 +1 @@
+invoice.tex
\ No newline at end of file
diff --git a/templates/print/marei/invoice_for_advance_payment.tex b/templates/print/marei/invoice_for_advance_payment.tex
new file mode 120000 (symlink)
index 0000000..b6a6ad8
--- /dev/null
@@ -0,0 +1 @@
+invoice.tex
\ No newline at end of file
index 90ccaff..79b33a8 100644 (file)
@@ -1,48 +1,57 @@
 \NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{kiviletter}[2020/04/24 Letter Layouts for Kivitendo]
+\ProvidesPackage{kiviletter}[2022/04/23 Letter Layouts for Kivitendo]
 
-\newif\if@kivi@infobox
-\newif\if@kivi@footer
-\DeclareOption{reffields}{\@kivi@infoboxfalse}
-\DeclareOption{infobox}{\@kivi@infoboxtrue}
-\DeclareOption{nofooter}{\@kivi@footerfalse}
-\DeclareOption{footer}{\@kivi@footertrue}
-\@kivi@infoboxtrue
-\@kivi@footertrue
+\RequirePackage{l3keys2e}
 
-\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{scrletter}}
+%Optionen vor den eigenen Paketoptionen hinzufügen, damit spätere diese ggf. überschreiben
+\PassOptionsToPackage{
+  fromlogo,
+  fromalign=right,
+  firstfoot=false,%Für einheitliche Randeinstellungen
+  refline=nodate,
+}{scrletter}
 
-\ProcessOptions\relax
+\ExplSyntaxOn
+\newif\if@kivi@infobox
+\newif\if@kivi@footer
+\keys_define:nn {kiviletter} {
+  infobox .choices:nn = {true,false} {\use:c {@kivi@infobox\l_keys_choice_tl}},
+  infobox .default:n = true,
+  infobox .initial:n = true,
+  reffields .meta:n = {infobox=false},
+  footer .choices:nn = {true,false} {\use:c {@kivi@footer\l_keys_choice_tl}},
+  footer .default:n = true,
+  footer .initial:n = true,
+  nofooter .meta:n = {footer=false},
+  unknown .code:n = \PassOptionsToPackage{\l_keys_key_str=#1}{scrletter},
+}
+\ExplSyntaxOff
 
+\ProcessKeysOptions{kiviletter}
 
-\RequirePackage{expl3}
 \RequirePackage{xparse}
 \RequirePackage{iftex}
-\KOMAoptions{fontsize=12pt}
+
 % Schriftart, Eingabelayout der Tastatur
 \ifPDFTeX
-       \RequirePackage[utf8]{inputenc}% Nur notwendig, wenn Basis älter als TL2018
-       \RequirePackage[T1]{fontenc}
-       \RequirePackage{lmodern}
+  \RequirePackage[utf8]{inputenc}% Nur notwendig, wenn Basis älter als TL2018
+  \RequirePackage[T1]{fontenc}
+  \RequirePackage{lmodern}
 
-       \RequirePackage{eurosym}
-       \DeclareUnicodeCharacter{20AC}{\euro}
+  \RequirePackage{eurosym}
+  \DeclareUnicodeCharacter{20AC}{\euro}
 \else
-       \RequirePackage{fontspec}
+  \RequirePackage{fontspec}
 \fi
 
 \RequirePackage{xltabular}
 \RequirePackage{booktabs}
 \RequirePackage{graphicx}
 
-
-
-\RequirePackage[fromlogo,fromalign=right,
-  firstfoot=false,%Für einheitliche Randeinstellungen
-  refline=nodate,
-       ]{scrletter}
+\RequirePackage{scrletter}
 \LoadLetterOption{DIN}
 
+\newkomavar{taxpoint}
 \newkomavar{transaction}
 \newkomavar[\lieferschein{}~\nr]{delivery}
 \newkomavar[\angebot{}~\nr]{quote}
 
 
 \DeclareNewLayer[
-foreground,
-hoffset=\useplength{toaddrhpos},
-voffset=\dimexpr\useplength{toaddrvpos}+\useplength{toaddrheight}+4\baselineskip,%sep to shippingaddressbox
-contents={\usebox\shippingAddressBox}
+  foreground,
+  hoffset=\useplength{toaddrhpos},
+  voffset=\dimexpr\useplength{toaddrvpos}+\useplength{toaddrheight}+4\baselineskip,%sep to shippingaddressbox
+  contents={\usebox\shippingAddressBox}
 ]{kivitendo.shippingaddress}
 
 \newpairofpagestyles{kivitendo.letter}{}
@@ -82,17 +91,17 @@ contents={\usebox\shippingAddressBox}
 \renewcommand*{\letterpagestyle}{kivitendo.letter}
 
 \DeclareNewPageStyleByLayers{kivitendo.letter.first}{
-       kivitendo.shippingaddress,
-       plain.kivitendo.letter.head.odd,plain.kivitendo.letter.head.even,plain.kivitendo.letter.head.oneside,%
-       plain.kivitendo.letter.foot.odd,plain.kivitendo.letter.foot.even,plain.kivitendo.letter.foot.oneside,%
+  kivitendo.shippingaddress,
+  plain.kivitendo.letter.head.odd,plain.kivitendo.letter.head.even,plain.kivitendo.letter.head.oneside,%
+  plain.kivitendo.letter.foot.odd,plain.kivitendo.letter.foot.even,plain.kivitendo.letter.foot.oneside,%
 }
 
 \setkomavar{backaddress}{\firma\ $\cdot$ \strasse\ $\cdot$ \ort}
 
 \setkomavar{firsthead}{
-       \if@logo
-       \rlap{\usekomavar{fromlogo}}%
-       \fi
+  \if@logo
+    \rlap{\usekomavar{fromlogo}}%
+  \fi
 }
 
 \@setplength{locwidth}{6cm}
@@ -103,101 +112,107 @@ contents={\usebox\shippingAddressBox}
 
 
 \cs_new:Nn \__kivi_set_colwidth:nn  {
-       \dim_set:cn {l_kivi_tab_#1_dim} {#2}
+  \dim_set:cn {l_kivi_tab_#1_dim} {#2}
 }
 
 
 \cs_new:Nn \__kivi_initialize_columns: {
-       \clist_map_inline:Nn \g_kivi_pricingtable_col_clist {
-               \bool_if_exist:cF {l_kivi_col_##1_bool} 
-               {
-                       \bool_new:c {l_kivi_col_##1_bool}
-                       \dim_new:c {l_kivi_tab_##1_dim}
-                       \keys_define:nn {kivi/PricingTable} {
-                               ##1 .choice:,
-                               ##1 / true .code:n = \bool_set_true:c {l_kivi_col_##1_bool},
-                               ##1 / false .code:n = \bool_set_false:c {l_kivi_col_##1_bool},
-                               ##1 / unknown .code:n = {
-                                       \bool_set_true:c {l_kivi_col_##1_bool}
-                                       \dim_set:cn {l_kivi_tab_##1_dim} {####1}
-                               },
-                               ##1 .default:n = true,
-                               ##1 .initial:n = true,
-                               ##1 / header .prop_put:c = {l_kivi_col_##1_prop},
-                               ##1 / colspec .prop_put:c = {l_kivi_col_##1_prop},
-                       }
-               }
-       }
+  \clist_map_inline:Nn \g_kivi_pricingtable_col_clist {
+    \bool_if_exist:cF {l_kivi_col_##1_bool}
+    {
+      \bool_new:c {l_kivi_col_##1_bool}
+      \dim_new:c {l_kivi_tab_##1_dim}
+      \keys_define:nn {kivi/PricingTable} {
+        ##1 .choice:,
+        ##1 / true .code:n = \bool_set_true:c {l_kivi_col_##1_bool},
+        ##1 / false .code:n = \bool_set_false:c {l_kivi_col_##1_bool},
+        ##1 / unknown .code:n = {
+            \bool_set_true:c {l_kivi_col_##1_bool}
+            \dim_set:cn {l_kivi_tab_##1_dim} {####1}
+          },
+        ##1 .default:n = true,
+        ##1 .initial:n = true,
+        ##1 / header .prop_put:c = {l_kivi_col_##1_prop},
+        ##1 / colspec .prop_put:c = {l_kivi_col_##1_prop},
+      }
+    }
+  }
 }
 
 \clist_new:N \g_kivi_pricingtable_col_clist
 
 \keys_define:nn {kivi/PricingTable} {
-       columns .code:n = 
-       \clist_gset:Nn \g_kivi_pricingtable_col_clist {#1}
-       \__kivi_initialize_columns:,
-       columns .initial:n = {pos, id, desc, amount, price, pricetotal},
+  columns .code:n =
+  \clist_gset:Nn \g_kivi_pricingtable_col_clist {#1}
+  \__kivi_initialize_columns:,
+  columns .initial:n = {pos, id, desc, amount, price, pricetotal},
+  unknown .code:n = \keys_set:no {kivi/Tabular} {\l_keys_key_str=#1}
 }
 
 % set default values for colwidth
 \keys_set:nn {kivi/PricingTable} {
-       pos=5ex,
-       id=4em,
-       amount=5em,
-       price=7em,
-       pricetotal=7em,
-%      desc=auto,
-       pos/header=\position,
-       id/header=\artikelnummer,
-       desc/header=\bezeichnung,
-       amount/header=\menge,
-       price/header=\einzelpreis,
-       pricetotal/header=\gesamtpreis,
-       price / colspec = Price,
-       pricetotal / colspec = Price ,
+  pos=5ex,
+  id=4em,
+  amount=5em,
+  price=7em,
+  pricetotal=7em,
+  %  desc=auto,
+  pos/header=\position,
+  id/header=\artikelnummer,
+  desc/header=\bezeichnung,
+  amount/header=\menge,
+  price/header=\einzelpreis,
+  pricetotal/header=\gesamtpreis,
+  price / colspec = Price,
+  pricetotal / colspec = Price ,
 }
 
 \dim_new:N \g_kivi_tabcolsep_dim
 \dim_gset:Nn \g_kivi_tabcolsep_dim {.5\tabcolsep}
+\setlength\tabcolsep{.5\tabcolsep}
 
 \prg_new_conditional:Nnn \kivi_if_Price_col:n {T} {
-       \prop_get:cnN {l_kivi_col_#1_prop} {colspec} \l_tmpa_tl
-       \exp_args:NV \tl_if_eq:nnTF \l_tmpa_tl {Price}
-               {\prg_return_true:}
-               {\prg_return_false:}
+  \prop_get:cnN {l_kivi_col_#1_prop} {colspec} \l_tmpa_tl
+  \exp_args:NV \tl_if_eq:nnTF \l_tmpa_tl {Price}
+  {\prg_return_true:}
+  {\prg_return_false:}
 }
 
 
 \cs_new:Nn \__kivi_calc_desc_column: {
-       \dim_zero:N \l_kivi_tab_desc_leftskip_dim
-       \dim_zero:N \l_kivi_tab_desc_dim
-       \bool_set_false:N \l_tmpa_bool
-       \tl_gclear:N \g_kivi_Pricing_colspec_tl
-       \clist_map_inline:Nn \g_kivi_pricingtable_col_clist {
-               \tl_if_eq:nnTF {##1} {desc}  {
-                       \dim_set:Nn \l_kivi_tab_desc_dim {
-                               \textwidth-\l_kivi_tab_desc_leftskip_dim
-                       }
-                       \bool_set_true:N \l_tmpa_bool
-                       \tl_gput_right:Nn \g_kivi_Pricing_colspec_tl {p{\l_kivi_tab_desc_dim}}
-               }{
-                       \bool_if:cT {l_kivi_col_##1_bool} {
-                               \bool_if:NTF \l_tmpa_bool {
-                                       \dim_sub:Nn \l_kivi_tab_desc_dim {
-                                               \dim_use:c {l_kivi_tab_##1_dim}+2\g_kivi_tabcolsep_dim
-                                       }
-                               }{
-                                       \dim_add:Nn \l_kivi_tab_desc_leftskip_dim {
-                                               \dim_use:c {l_kivi_tab_##1_dim}+2\g_kivi_tabcolsep_dim
-                                       }
-                               }
-                               \tl_gput_right:Nn \g_kivi_Pricing_colspec_tl {K{\dim_use:c {l_kivi_tab_##1_dim}}}
-                               \kivi_if_Price_col:nT {##1} {\tl_gput_right:Nn \g_kivi_Pricing_colspec_tl {<{\__kivi_tab_column_currency:}}}
-                       }
-               }
-       }
-       \tl_gput_left:Nn \g_kivi_Pricing_colspec_tl {@{}}
-       \tl_gput_right:Nn \g_kivi_Pricing_colspec_tl {@{}}
+  \bool_if:NTF \g__kivi_Tabular_rowcolor_bool
+  {\dim_set:Nn \l_kivi_tab_desc_leftskip_dim {2\g_kivi_tabcolsep_dim}}
+  {\dim_zero:N \l_kivi_tab_desc_leftskip_dim}
+  \dim_zero:N \l_kivi_tab_desc_dim
+  \bool_set_false:N \l_tmpa_bool
+  \tl_gclear:N \g_kivi_Pricing_colspec_tl
+  \clist_map_inline:Nn \g_kivi_pricingtable_col_clist {
+    \tl_if_eq:nnTF {##1} {desc}  {
+      \dim_set:Nn \l_kivi_tab_desc_dim {
+        \textwidth-\l_kivi_tab_desc_leftskip_dim
+      }
+      \bool_set_true:N \l_tmpa_bool
+      \tl_gput_right:Nn \g_kivi_Pricing_colspec_tl {p{\l_kivi_tab_desc_dim}}
+    }{
+      \bool_if:cT {l_kivi_col_##1_bool} {
+        \bool_if:NTF \l_tmpa_bool {
+          \dim_sub:Nn \l_kivi_tab_desc_dim {
+            \dim_use:c {l_kivi_tab_##1_dim}+2\g_kivi_tabcolsep_dim
+          }
+        }{
+          \dim_add:Nn \l_kivi_tab_desc_leftskip_dim {
+            \dim_use:c {l_kivi_tab_##1_dim}+2\g_kivi_tabcolsep_dim
+          }
+        }
+        \tl_gput_right:Nn \g_kivi_Pricing_colspec_tl {K{\dim_use:c {l_kivi_tab_##1_dim}}}
+        \kivi_if_Price_col:nT {##1} {\tl_gput_right:Nn \g_kivi_Pricing_colspec_tl {<{\__kivi_tab_column_currency:}}}
+      }
+    }
+  }
+  \bool_if:NF \g__kivi_Tabular_rowcolor_bool {
+    \tl_gput_left:Nn \g_kivi_Pricing_colspec_tl {@{}}
+    \tl_gput_right:Nn \g_kivi_Pricing_colspec_tl {@{}}
+  }
 }
 
 \newcolumntype{K}[1]{>{\raggedleft\arraybackslash}p{#1}}
@@ -207,101 +222,145 @@ contents={\usebox\shippingAddressBox}
 \tcbuselibrary{breakable, skins}
 
 \tcb@new@skin{kivi@LT}{base@unbroken,%
-       frame~engine=empty,interior~titled~engine=empty,interior~engine=empty,segmentation~engine=empty,title~engine=empty,%
-       skin~first=kivi@LT@first,skin~middle=kivi@LT@middle,skin~last=kivi@LT@last,
-       underlay~first~and~middle={
-               \node[anchor=north]  at (interior.north)  {\csname box_use:c\endcsname  {g_kivi_LT@head_box}};
-               \node[anchor=south]  at (interior.south)  {\csname box_use:c\endcsname  {g_kivi_LT@foot_box}};
-       },
-       underlay~unbroken~and~last={
-       \node[anchor=north]  at (interior.north)  {\csname box_use:c\endcsname  {g_kivi_LT@head_box}};
-       \node[anchor=south]  at (interior.south)  {\csname box_use:c\endcsname  {g_kivi_LT@lastfoot_box}};
-       },
-       boxsep=0pt,
-       boxrule=0pt,
-       left=0pt,
-       right=0pt,
-       bottom=\box_ht:N  \g_kivi_LT@foot_box+\box_dp:N  \g_kivi_LT@foot_box + \aboverulesep,
-       top=\box_ht:N  \g_kivi_LT@head_box+\box_dp:N  \g_kivi_LT@head_box +\belowrulesep,
-       parbox=false,
+  frame~engine=empty,interior~titled~engine=empty,interior~engine=empty,segmentation~engine=empty,title~engine=empty,%
+  skin~first=kivi@LT@first,skin~middle=kivi@LT@middle,skin~last=kivi@LT@last,
+  underlay~first~and~middle={
+    \node[anchor=north]  at (interior.north)  {\csname box_use:c\endcsname  {g_kivi_LT@head_box}};
+    \node[anchor=south]  at (interior.south)  {\csname box_use:c\endcsname  {g_kivi_LT@foot_box}};
+},
+  underlay~unbroken~and~last={
+    \node[anchor=north]  at (interior.north)  {\csname box_use:c\endcsname  {g_kivi_LT@head_box}};
+    \node[anchor=south]  at (interior.south)  {\csname box_use:c\endcsname  {g_kivi_LT@lastfoot_box}};
+  },
+  boxsep=0pt,
+  boxrule=0pt,
+  left=0pt,
+  right=0pt,
+  bottom=\box_ht:N  \g_kivi_LT@foot_box+\box_dp:N  \g_kivi_LT@foot_box + \aboverulesep,
+  top=\box_ht:N  \g_kivi_LT@head_box+\box_dp:N  \g_kivi_LT@head_box +\belowrulesep,
+  parbox=false,
 }
 
 \tcb@new@skin{kivi@LT@first}{base@first,%
-       frame~engine=empty,interior~titled~engine=empty,interior~engine=empty,segmentation~engine=empty,title~engine=empty,%
-       skin~first=kivi@LT@first,skin~middle=kivi@LT@middle,skin~last=kivi@LT@middle,
+  frame~engine=empty,interior~titled~engine=empty,interior~engine=empty,segmentation~engine=empty,title~engine=empty,%
+  skin~first=kivi@LT@first,skin~middle=kivi@LT@middle,skin~last=kivi@LT@middle,
 }
 
 \tcb@new@skin{kivi@LT@middle}{base@middle,%
-       frame~engine=empty,interior~titled~engine=empty,interior~engine=empty,segmentation~engine=empty,title~engine=empty,%
-       skin~first=kivi@LT@middle,skin~middle=kivi@LT@middle,skin~last=kivi@LT@middle,
+  frame~engine=empty,interior~titled~engine=empty,interior~engine=empty,segmentation~engine=empty,title~engine=empty,%
+  skin~first=kivi@LT@middle,skin~middle=kivi@LT@middle,skin~last=kivi@LT@middle,
 }
 
 \tcb@new@skin{kivi@LT@last}{base@last,%
-       frame~engine=empty,interior~titled~engine=empty,interior~engine=empty,segmentation~engine=empty,title~engine=empty,%
-       skin~first=kivi@LT@middle,skin~middle=kivi@LT@middle,skin~last=kivi@LT@last,
+  frame~engine=empty,interior~titled~engine=empty,interior~engine=empty,segmentation~engine=empty,title~engine=empty,%
+  skin~first=kivi@LT@middle,skin~middle=kivi@LT@middle,skin~last=kivi@LT@last,
 }
 
 \tcbset{kivi@LT/.style={skin=kivi@LT}}%
 
-
-
 \seq_new:N \l_kivi_PricingTable_seq
 \seq_new:N \l_kivi_columns_seq
 \seq_new:N \g_kivi_extraDescription_seq
+
+\int_new:N \g__kivi_PricingTable_rowcolor_int
+\dim_new:N \l__kivi_fboxsep_dim
+\dim_set:Nn \l__kivi_fboxsep_dim {\g_kivi_tabcolsep_dim}
+
+%colorbox variant to only add vertical spacing
+%based on colorbox definition from xcolor.sty
+%% ----------------------------------------------------------------
+%% Copyright (C) 2003-2016 by Dr. Uwe Kern <xcolor at ukern dot de>
+%% ----------------------------------------------------------------
+%% This variant of colorbox adds a space of \l__kivi_fboxsep_dim along the vertical axes but no horizontal space
+\def\kivi@tabcolorbox#1#{\protect\kivi@tabcolor@box{#1}}
+
+\def\kivi@tabcolor@box#1#2{
+  \tl_if_empty:oTF {#2}
+  \kivi@nocolor@b@x
+  \kivi@color@b@x
+  \relax{\color#1{#2}}
+}
+\long\def\kivi@color@b@x#1#2#3%
+{\leavevmode
+  \setbox\z@\hbox{{\set@color#3}}%
+  \dimen@\ht\z@\advance\dimen@\l__kivi_fboxsep_dim\ht\z@\dimen@
+  \dimen@\dp\z@\advance\dimen@\l__kivi_fboxsep_dim\dp\z@\dimen@
+  {#1{#2\color@block{\wd\z@}{\ht\z@}{\dp\z@}\box\z@}}}
+
+\long\def\kivi@nocolor@b@x#1#2#3%
+{\leavevmode
+  \setbox\z@\hbox{#3}%
+  \dimen@\ht\z@\advance\dimen@\l__kivi_fboxsep_dim\ht\z@\dimen@
+  \dimen@\dp\z@\advance\dimen@\l__kivi_fboxsep_dim\dp\z@\dimen@
+  {\box\z@}}
+
+%%%
+
+
 \newcommand{\FakeTable}[1]{
-       \par
-       \seq_set_split:Nnn \l_kivi_PricingTable_seq {\tabularnewline} {#1}
-       \seq_remove_all:Nn \l_kivi_PricingTable_seq {}
-       \begingroup
-       \setlength{\parskip}{\c_zero_dim}
-       \let\ExtraDescription\__kivi_addExtraDescription:n
-       \setlength{\tabcolsep}{\g_kivi_tabcolsep_dim}
-       \seq_map_inline:Nn \l_kivi_PricingTable_seq {
-               \seq_set_split:Nnn  \l_kivi_columns_seq {&} {##1}
-       \seq_gclear:N \g_kivi_extraDescription_seq
-       \exp_args:Nnx \use:n {\tabular[t]}\g_kivi_Pricing_colspec_tl
-               \seq_pop_left:NN \__l_FakeTable_columns_seq \l_tmpa_tl
-               \seq_item:Nn \l_kivi_columns_seq {\l_tmpa_tl}
-               \seq_map_inline:Nn \__l_FakeTable_columns_seq {
-                       &\seq_item:Nn \l_kivi_columns_seq {####1}
-               }
-       \endtabular
-       \seq_if_empty:NTF \g_kivi_extraDescription_seq
-       {\par}
-       {\par\nopagebreak
-       \begingroup
-       \setlength{\hsize}{\dimexpr\l_kivi_tab_desc_dim+\l_kivi_tab_desc_leftskip_dim}
-       \setlength{\leftskip}{\l_kivi_tab_desc_leftskip_dim}
-       \usekomafont{extraDescription}
-       \seq_use:Nn \g_kivi_extraDescription_seq {\\}
-       \par
-       \endgroup
-       }
-       }
-       \endgroup
+  \par
+  \seq_set_split:Nnn \l_kivi_PricingTable_seq {\tabularnewline} {#1}
+  \seq_remove_all:Nn \l_kivi_PricingTable_seq {}
+  \begingroup
+  \setlength{\parskip}{\c_zero_dim}
+  \let\ExtraDescription\__kivi_addExtraDescription:n
+  \setlength{\tabcolsep}{\g_kivi_tabcolsep_dim}
+  \seq_map_inline:Nn \l_kivi_PricingTable_seq {
+    \if_mode_horizontal: \par \fi
+    \bool_if:NT \g__kivi_Tabular_rowcolor_bool {
+      \int_gincr:N \g__kivi_PricingTable_rowcolor_int
+      \int_if_odd:nTF {\g__kivi_PricingTable_rowcolor_int}
+      {\nointerlineskip\kivi@tabcolorbox{\g__kivi_Tabular_rowcolor_odd_tl}}
+      {\nointerlineskip\kivi@tabcolorbox{\g__kivi_Tabular_rowcolor_even_tl}}
+    }
+    {\parbox{\linewidth}{
+        \seq_set_split:Nnn  \l_kivi_columns_seq {&} {##1}
+        \seq_gclear:N \g_kivi_extraDescription_seq
+        \exp_args:Nnx \use:n {\tabular[t]}\g_kivi_Pricing_colspec_tl
+        \seq_pop_left:NN \__l_FakeTable_columns_seq \l_tmpa_tl
+        \seq_item:Nn \l_kivi_columns_seq {\l_tmpa_tl}
+        \seq_map_inline:Nn \__l_FakeTable_columns_seq {
+          &\seq_item:Nn \l_kivi_columns_seq {####1}
+        }
+        \endtabular
+        \seq_if_empty:NTF \g_kivi_extraDescription_seq
+        {\par}
+        {\par\nopagebreak
+          \begingroup
+          \setlength{\leftskip}{\dim_eval:n {\bool_if:NT \g__kivi_Tabular_rowcolor_bool {-\tabcolsep} +\l_kivi_tab_desc_leftskip_dim}}
+          \setlength{\hsize}{\dim_eval:n {\l_kivi_tab_desc_dim+\leftskip}}
+          \usekomafont{extraDescription}
+          \seq_use:Nn \g_kivi_extraDescription_seq {\\}
+          \par
+          \endgroup
+        }
+      }}
+  }
+  \endgroup\par
+  \l__kivi_Tabular_rowsep_tl
 }
 
 
 \seq_new:N  \__l_FakeTable_columns_seq
 \cs_new:Nn \__kivi_setup_FakeTable: {
-       \seq_clear:N \__l_FakeTable_columns_seq
-       \int_zero:N \l_tmpa_int
-       \clist_map_inline:Nn \g_kivi_pricingtable_col_clist {
-               \int_incr:N \l_tmpa_int
-               \bool_if:cT {l_kivi_col_##1_bool} {\seq_put_right:Nx \__l_FakeTable_columns_seq {\int_use:N \l_tmpa_int}}
-       }
+  \seq_clear:N \__l_FakeTable_columns_seq
+  \int_zero:N \l_tmpa_int
+  \clist_map_inline:Nn \g_kivi_pricingtable_col_clist {
+    \int_incr:N \l_tmpa_int
+    \bool_if:cT {l_kivi_col_##1_bool} {\seq_put_right:Nx \__l_FakeTable_columns_seq {\int_use:N \l_tmpa_int}}
+  }
 }
 
 \tl_new:N \g_kivi_Pricing_colspec_tl
 \tl_gset:Nn \g_kivi_Pricing_colspec_tl {
-       @{}
-       \bool_if:NT \l_kivi_col_pos_bool {p{\l_kivi_tab_pos_dim}}
-       \bool_if:NT \l_kivi_col_id_bool {p{\l_kivi_tab_id_dim}}
-       p{\l_kivi_tab_desc_dim}
-       \bool_if:NT \l_kivi_col_amount_bool {\exp_not:n {>{\raggedleft\arraybackslash}p{\l_kivi_tab_amount_dim}}}
-       \bool_if:NT \l_kivi_col_price_bool {\exp_not:n {>{\raggedleft\arraybackslash}p{\l_kivi_tab_price_dim}<{\__kivi_tab_column_currency:}}}
-       \bool_if:NT \l_kivi_col_pricetotal_bool {\exp_not:n {>{\raggedleft\arraybackslash}p{\l_kivi_tab_pricetotal_dim}<{\__kivi_tab_column_currency:}}}
-       @{}
+  \bool_if:NF \g__kivi_Tabular_rowcolor_bool {@{}}
+  \bool_if:NT \l_kivi_col_pos_bool {p{\l_kivi_tab_pos_dim}}
+  \bool_if:NT \l_kivi_col_id_bool {p{\l_kivi_tab_id_dim}}
+  p{\l_kivi_tab_desc_dim}
+  \bool_if:NT \l_kivi_col_amount_bool {\exp_not:n {>{\raggedleft\arraybackslash}p{\l_kivi_tab_amount_dim}}}
+  \bool_if:NT \l_kivi_col_price_bool {\exp_not:n {>{\raggedleft\arraybackslash}p{\l_kivi_tab_price_dim}<{\__kivi_tab_column_currency:}}}
+  \bool_if:NT \l_kivi_col_pricetotal_bool {\exp_not:n {>{\raggedleft\arraybackslash}p{\l_kivi_tab_pricetotal_dim}<{\__kivi_tab_column_currency:}}}
+  \bool_if:NF \g__kivi_Tabular_rowcolor_bool {@{}}
 }
 
 \cs_new_protected:Nn \__kivi_tab_column_currency: {\,\currency}
@@ -310,98 +369,132 @@ contents={\usebox\shippingAddressBox}
 \cs_set_eq:NN \__kivi_tab_column_body_currency:  \__kivi_tab_column_currency:
 
 \clist_map_inline:nn {head, foot, firsthead, lastfoot} {%TODO reduce
-       \box_new:c {g_kivi_LT@#1_box}
+  \box_new:c {g_kivi_LT@#1_box}
 }
 
 \newkomafont{PricingTableHeader}{\bfseries}
 
 \cs_new:Nn \__kivi_setup_LT_boxes: {
-       \__kivi_calc_desc_column:
-       \hbox_gset:Nn \g_kivi_LT@head_box {
-               \setlength{\tabcolsep}{\g_kivi_tabcolsep_dim}
-               \exp_args:Nnx \use:n {\tabular[b]}\g_kivi_Pricing_colspec_tl
-               \__kivi_PricingTabular_header:
-               \endtabular
-       }
-       \hbox_gset:Nn \g_kivi_LT@foot_box {
-               \raisebox{\depth}{
-                       \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}r@{}}
-                               \midrule
-                               \strut\weiteraufnaechsterseite
-                       \end{tabular*}
-               }
-       }
-       \hbox_gset:Nn \g_kivi_LT@lastfoot_box {
-               \raisebox{\dimexpr\depth+\baselineskip}[0pt][0pt]{
-                       \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}r@{}}
-                               \bottomrule
-                       \end{tabular*}
-               }
-       }
+  \__kivi_calc_desc_column:
+  \hbox_gset:Nn \g_kivi_LT@head_box {
+    \setlength{\tabcolsep}{\g_kivi_tabcolsep_dim}
+    \bool_if:NT \g__kivi_Tabular_rowcolor_bool {\kivi@tabcolorbox{\g__kivi_Tabular_rowcolor_header_tl}}%
+    {
+      \exp_args:Nnx \use:n {\tabular[b]}\g_kivi_Pricing_colspec_tl
+      \__kivi_PricingTabular_header:
+      \endtabular
+    }
+  }
+  \hbox_gset:Nn \g_kivi_LT@foot_box {
+    \begin{tabular*}{\textwidth}[t]{@{\extracolsep{\fill}}r@{\bool_if:NT \g__kivi_Tabular_rowcolor_bool {\hskip\tabcolsep}}}
+      \bool_if:NTF \g__kivi_Tabular_rowcolor_bool
+      {\hline\noalign{\vskip1pt}}
+      \midrule
+      \strut\weiteraufnaechsterseite
+    \end{tabular*}
+  }
+  \hbox_gset:Nn \g_kivi_LT@lastfoot_box {
+    \raisebox{\dimexpr\depth+\baselineskip}[0pt][0pt]{
+      \begin{tabular*}{\textwidth}{@{\bool_if:NT \g__kivi_Tabular_rowcolor_bool {\hskip\tabcolsep}\extracolsep{\fill}}r@{\bool_if:NT \g__kivi_Tabular_rowcolor_bool {\hskip\tabcolsep}}}
+        \bool_if:NF \g__kivi_Tabular_rowcolor_bool \bottomrule
+      \end{tabular*}
+    }
+  }
 }
 
 
 %Macht es sinn hier eine Variante zu machen, in der alle Spalten Belegbar sind?
-\newenvironment{PricingTotal}{
-       \par\nointerlineskip
-       \unskip
-       \tabular[t]{@{}p{\dim_eval:n {\linewidth-\l_kivi_tab_pricetotal_dim-2\tabcolsep}}P{\l_kivi_tab_pricetotal_dim}@{}}
-       \midrule
+\NewDocumentEnvironment{PricingTotal}{+b}{
+  \par\nointerlineskip
 }{
-       \endtabular
+  \bool_if:NT \g__kivi_Tabular_rowcolor_bool   {\nointerlineskip\kivi@tabcolorbox{\g__kivi_Tabular_rowcolor_PricingTotal_tl}}
+  {
+    \tabular[t]{
+      @{\bool_if:NT \g__kivi_Tabular_rowcolor_bool {\hskip\tabcolsep}}
+      p{\dim_eval:n {\linewidth-\l_kivi_tab_pricetotal_dim-\bool_if:NTF \g__kivi_Tabular_rowcolor_bool {4}{2}\tabcolsep}}P{\l_kivi_tab_pricetotal_dim}@{\bool_if:NT \g__kivi_Tabular_rowcolor_bool {\hskip\tabcolsep}}
+    }
+    \l__kivi_Tabular_PricingTotal_topsep_tl
+    #1
+    \endtabular
+  }
 }
 
+\tl_new:N \l__kivi_Tabular_PricingTotal_topsep_tl
+%TODO
+\tl_set:Nn \l__kivi_Tabular_PricingTotal_topsep_tl {\bool_if:NF \g__kivi_Tabular_rowcolor_bool \midrule}
 
 \newcommand*\ExtraDescription{
-       \PackageError{kiviletter}{The~command~\string\ExtraDescription\space~may~be~only~used~inside~the~\string\FakeTable\space~environment.}{See~documentation~for~details}
+  \PackageError{kiviletter}{The~command~\string\ExtraDescription\space~may~be~only~used~inside~the~\string\FakeTable\space~environment.}{See~documentation~for~details}
 }
 
 
 \cs_new:Nn \__kivi_addExtraDescription:n {\seq_gput_right:Nn \g_kivi_extraDescription_seq {#1}}
 
 \newenvironment{PricingTabular}[1][]{
-       \begingroup
-       \dim_set:Nn \parskip {\c_zero_dim}
-       \tl_if_empty:nF {#1} {\keys_set:nn {kivi/PricingTable} {#1}}
-       \setlength{\tabcolsep}{\g_kivi_tabcolsep_dim}
-       \__kivi_calc_desc_column:
-       \exp_args:Nx \longtable \g_kivi_Pricing_colspec_tl
-       % Tabellenkopf
-       \__kivi_PricingTabular_header:
-       \endhead
-       \midrule
-       \rlap{\makebox[\textwidth][r]{\weiteraufnaechsterseite}}\\
-       \endfoot
-       \bottomrule
-       \endlastfoot
+  \begingroup
+  \dim_set:Nn \parskip {\c_zero_dim}
+  \tl_if_empty:nF {#1} {\keys_set:nn {kivi/PricingTable} {#1}}
+  \setlength{\tabcolsep}{\g_kivi_tabcolsep_dim}
+  \__kivi_calc_desc_column:
+  \exp_args:Nx \longtable \g_kivi_Pricing_colspec_tl
+  % Tabellenkopf
+  \__kivi_PricingTabular_header:
+  \endhead
+  \midrule
+  \rlap{\makebox[\textwidth][r]{\weiteraufnaechsterseite}}\\
+  \endfoot
+  \bool_if:NF \g__kivi_Tabular_rowcolor_bool \bottomrule
+  \endlastfoot
 }{
-       \endlongtable
-       \endgroup
+  \endlongtable
+  \endgroup
 }
 
 \cs_set:Nn \__kivi_PricingTabular_header: {
-       \toprule
-       \cs_gset_eq:NN \__kivi_tab_column_currency: \__kivi_tab_column_header_currency:
-       \bool_set_false:N \l_tmpa_bool
-       \clist_map_inline:Nn \g_kivi_pricingtable_col_clist     {
-               \bool_if:cT {l_kivi_col_##1_bool} {
-                       \bool_if:NT \l_tmpa_bool {&}
-                       \bool_set_true:N \l_tmpa_bool
-                       \usekomafont{PricingTableHeader}
-                       \prop_item:cn {l_kivi_col_##1_prop} {header}
-               }
-       }
-       \cs_gset_eq:NN \__kivi_tab_column_currency: \__kivi_tab_column_body_currency:
-       \\
-       \midrule
+  \bool_if:NTF \g__kivi_Tabular_rowcolor_bool {\noalign{\skip_vertical:n {\dp\strutbox}}}\toprule
+  \cs_gset_eq:NN \__kivi_tab_column_currency: \__kivi_tab_column_header_currency:
+  \bool_set_false:N \l_tmpa_bool
+  \clist_map_inline:Nn \g_kivi_pricingtable_col_clist  {
+    \bool_if:cT {l_kivi_col_##1_bool} {
+      \bool_if:NT \l_tmpa_bool {&}
+      \bool_set_true:N \l_tmpa_bool
+      \usekomafont{PricingTableHeader}
+      \prop_item:cn {l_kivi_col_##1_prop} {header}
+    }
+  }
+  \cs_gset_eq:NN \__kivi_tab_column_currency: \__kivi_tab_column_body_currency:
+  \\
+  \bool_if:NF \g__kivi_Tabular_rowcolor_bool \midrule
 }
 
+\newkomafont{tablehead}{\bfseries}
 
 \keys_define:nn {kivi/SimpleTabular} {
-       colspec .tl_set:N =\l_kivi_SimpleTabular_colspec_tl,
-       colspec .initial:n = {rrX},
-       headline .tl_set:N = \l_kivi_SimpleTabular_headline_tl,
-       headline .initial:n = {\bfseries\position & \bfseries\menge & \bfseries\bezeichnung},
+  colspec .tl_set:N =\l_kivi_SimpleTabular_colspec_tl,
+  colspec .initial:n = {rrX},
+  headline .tl_set:N = \l_kivi_SimpleTabular_headline_tl,
+  headline .initial:n = {\usekomafont{tablehead}\position & \usekomafont{tablehead}\menge & \usekomafont{tablehead}\bezeichnung},
+}
+
+\keys_define:nn {kivi/Tabular} {
+  color-rows .bool_gset:N =  \g__kivi_Tabular_rowcolor_bool ,
+  color-rows .initial:n = false,
+  color-rows .default:n = true,
+  rowcolor-odd .tl_gset:N = \g__kivi_Tabular_rowcolor_odd_tl,
+  rowcolor-odd .initial:n = black!10,
+  rowcolor-even .tl_gset:N = \g__kivi_Tabular_rowcolor_even_tl,
+  rowcolor-even .initial:n =,
+  rowcolor-header .tl_gset:N = \g__kivi_Tabular_rowcolor_header_tl,
+  rowcolor-header .initial:n = black!35,
+  rowcolor-total .tl_gset:N = \g__kivi_Tabular_rowcolor_PricingTotal_tl,
+  rowcolor-total .initial:n = black!35,
+  rowsep .tl_set:N =\l__kivi_Tabular_rowsep_tl,
+  rowsep .initial:n = ,
+  hrule .meta:n = {
+    rowsep={
+      \vskip\aboverulesep
+      \leavevmode\hrule\@height\lightrulewidth
+      \vskip\belowrulesep}},
 }
 
 \newcommand*{\SetupSimpleTabular}[1]{\keys_set:nn {kivi/SimpleTabular} {#1}}
@@ -409,28 +502,30 @@ contents={\usebox\shippingAddressBox}
 
 \newenvironment{SimpleTabular}[1][]
 {
-       \tl_if_in:nnTF {#1} {=} {\keys_set:nn {kivi/SimpleTabular} {#1}} {\tl_if_empty:nF {#1} {\tl_set:Nn \l_kivi_SimpleTabular_headline_tl {#1}}}
-       \setlength{\tabcolsep}{\g_kivi_tabcolsep_dim}
-       \dim_set:Nn \parskip {\c_zero_dim}
-       \tl_put_right:Nn \l_kivi_SimpleTabular_colspec_tl {@{}}
-       \tl_put_left:Nn \l_kivi_SimpleTabular_colspec_tl {@{}}
-       \exp_args:NnV \xltabular{\linewidth}\l_kivi_SimpleTabular_colspec_tl
-               \toprule
-               \cs_gset_eq:NN \__kivi_tab_column_currency: \__kivi_tab_column_header_currency:
-               \l_kivi_SimpleTabular_headline_tl
-               \\
-               \noalign{\cs_gset_eq:NN \__kivi_tab_column_currency: \__kivi_tab_column_body_currency:}
-               \midrule
-       \endhead
-               \midrule
-               \rlap{\makebox[\textwidth][r]{\weiteraufnaechsterseite}}\\
-       \endfoot
-               \bottomrule
-       \endlastfoot
-       \ignorespaces
+  \tl_if_in:nnTF {#1} {=} {\keys_set:nn {kivi/SimpleTabular} {#1}} {\tl_if_empty:nF {#1} {\tl_set:Nn \l_kivi_SimpleTabular_headline_tl {#1}}}
+  \setlength{\tabcolsep}{\g_kivi_tabcolsep_dim}
+  \dim_set:Nn \parskip {\c_zero_dim}
+  \bool_if:NF \g__kivi_Tabular_rowcolor_bool {
+    \tl_put_right:Nn \l_kivi_SimpleTabular_colspec_tl {@{}}
+    \tl_put_left:Nn \l_kivi_SimpleTabular_colspec_tl {@{}}
+  }
+  \exp_args:NnV \xltabular{\linewidth}\l_kivi_SimpleTabular_colspec_tl
+  \toprule
+  \cs_gset_eq:NN \__kivi_tab_column_currency: \__kivi_tab_column_header_currency:
+  \l_kivi_SimpleTabular_headline_tl
+  \\
+  \noalign{\cs_gset_eq:NN \__kivi_tab_column_currency: \__kivi_tab_column_body_currency:}
+  \midrule
+  \endhead
+  \midrule
+  \rlap{\makebox[\textwidth][r]{\weiteraufnaechsterseite}}\\
+  \endfoot
+  \bool_if:NF \g__kivi_Tabular_rowcolor_bool \bottomrule
+  \endlastfoot
+  \ignorespaces
 }{
-       \def\@currenvir{tabularx}
-       \endxltabular
+  \def\@currenvir{tabularx}
+  \endxltabular
 }
 
 %PricingTabular* kann automatisch spalten ignorieren
@@ -439,78 +534,85 @@ contents={\usebox\shippingAddressBox}
 % analog ist dies für pos, amount, price, pricetotal möglich.
 % Die Spalte der Bezeichnung ist nicht deaktivierbar
 \newenvironment{PricingTabular*}[1][]{
-       \tl_if_empty:nF {#1} {\keys_set:nn {kivi/PricingTable} {#1}}
-       \__kivi_setup_LT_boxes:
-       \__kivi_setup_FakeTable:
-       \dim_set:Nn \parskip {\c_zero_dim}
-       \PricingTabularBox\ignorespaces
-}{\endPricingTabularBox}
+  \int_gzero:N \g__kivi_PricingTable_rowcolor_int
+  \tl_if_empty:nF {#1} {\keys_set:nn {kivi/PricingTable} {#1}}
+  \__kivi_setup_LT_boxes:
+  \__kivi_setup_FakeTable:
+  \dim_set:Nn \parskip {\c_zero_dim}
+  \PricingTabularBox\ignorespaces
+}{\endPricingTabularBox
+  %compensate footer spacing
+  \skip_vertical:n {-\box_ht:N  \g_kivi_LT@foot_box-\box_dp:N  \g_kivi_LT@foot_box}
+}
 
 \newtcolorbox{PricingTabularBox}{breakable,skin=kivi@LT}
 
 \if@kivi@infobox
 
-       \def\locationsep{:}
-
-       \NewDocumentCommand{\locationentry}{som}{
-               \Ifkomavarempty{#3}{}{
-               \IfBooleanTF {#1} {
-                       \strut
-                       \IfNoValueTF {#2}
-                               {\usekomavar*{#3}}
-                               {#2}
-                       \locationsep
-                       \hfill\strut\space
-                       \hbox_set:Nn \l_tmpa_box {\usekomavar{#3}}
-                       \dim_compare:nTF {\box_wd:N \l_tmpa_box>\linewidth}
-                               {\newline\hspace*{\fill}\llap}
-                               {\hspace*{\fill}}
-                               {\box_use:N \l_tmpa_box\strut}
-               }{
-                       \@hangfrom{\strut
-                               \IfNoValueTF {#2}
-                                       {\usekomavar*{#3}}
-                                       {#2}\locationsep~
-                       }{
-                               \parbox[t]{\dimexpr\linewidth-\hangindent}{
-                                       \raggedleft
-                                       \usekomavar{#3}\strut
-                               }
-                       }
-               }
-               }
-               \par
-       }
-
-
-\setkomavar{location}{
-       \Ifkomavarempty{transaction}{}{
-       \bfseries
-       \usekomavar{transaction}
-       }
-       \par
-       \medskip
-       \parbox{\useplength{locwidth}}{
-               \locationentry{date}
-               \locationentry{myref}
-               \locationentry{customer}
-               \locationentry{yourref}
-               \locationentry{delivery}
-               \locationentry{quote}
-               \locationentry{orderID}
-               \locationentry{projectID}
-               \locationentry[\ansprechpartner]{fromname}
-               \locationentry{fromphone}
-               \locationentry*{fromemail}
-       }
-}
-\removereffields
-\AtBeginLetter{
-       \ifdim\ht\shippingAddressBox>\z@
-       \@addtoplength{refvpos}{\dimexpr\ht\shippingAddressBox+\dp\shippingAddressBox}
-       \@addtoplength{refvpos}{4\baselineskip}%sep between address boxes
-       \fi
-}
+  \def\locationsep{:}
+
+  \NewDocumentCommand{\locationentry}{som}{
+    \Ifkomavarempty{#3}{}{
+      \IfBooleanTF {#1} {
+        \strut
+        \IfNoValueTF {#2}
+        {\usekomavar*{#3}}
+        {#2}
+        \locationsep
+        \hfill\strut\space
+        \hbox_set:Nn \l_tmpa_box {\usekomavar{#3}}
+        \dim_compare:nTF {\box_wd:N \l_tmpa_box>\linewidth}
+        {\newline\hspace*{\fill}\llap}
+        {\hspace*{\fill}}
+        {\box_use:N \l_tmpa_box\strut}
+      }{
+        \@hangfrom{\strut
+          \IfNoValueTF {#2}
+          {\usekomavar*{#3}}
+          {#2}\locationsep~
+        }{
+          \parbox[t]{\dimexpr\linewidth-\hangindent}{
+            \raggedleft
+            \usekomavar{#3}\strut
+          }
+        }
+      }
+    }
+    \par
+  }
+
+  \newkomafont{transaction}{\bfseries}
+
+  \setkomavar{location}{
+    \Ifkomavarempty{transaction}{}{{
+          \usekomafont{transaction}
+          \usekomavar{transaction}
+        }
+    }
+    \par
+    \medskip
+    \parbox{\useplength{locwidth}}{
+      \locationentry{date}
+      \locationentry{myref}
+      \locationentry{customer}
+      \locationentry{yourref}
+      \locationentry{delivery}
+      \locationentry{quote}
+      \locationentry{orderID}
+      \locationentry{projectID}
+      \locationentry{taxpoint}
+      \locationentry[\ansprechpartner]{fromname}
+      \locationentry{fromphone}
+      \locationentry*{fromemail}
+    }
+  }
+  \removereffields
+  \AtBeginLetter{
+    \ifdim\ht\shippingAddressBox>\z@
+      \@addtoplength{refvpos}{\dimexpr\ht\shippingAddressBox+\dp\shippingAddressBox}
+      \@addtoplength{refvpos}{4\baselineskip}%sep between address boxes
+    \fi
+  }
 
 \fi
 
@@ -521,42 +623,56 @@ contents={\usebox\shippingAddressBox}
 %Definitionen für die insettings.tex
 
 \newcommand*{\setupIdentpath}[1]{
-       \int_set:Nn \l_kivi_tmp_int {1}
-       \bool_set_true:N \l_kivi_tmp_bool
-       \bool_while_do:Nn \l_kivi_tmp_bool {
-               \file_if_exist:nTF {firma\int_use:N \l_kivi_tmp_int/ident.tex}
-               {
-                       \exp_args:Nf \str_if_in:nnTF {#1} {Firma\int_use:N \l_kivi_tmp_int}
-                       {
-                               \newcommand*{\identpath}{firma\int_use:N \l_kivi_tmpa_int}
-                               \bool_set_false:N \l_kivi_tmp_bool
-                       }
-                       {\int_incr:N \l_kivi_tmp_int}
-               }
-               {
-                       \bool_set_false:N \l_kivi_tmp_bool
-                       \newcommand*{\identpath}{firma}
-               }
-       }
+  \int_set:Nn \l_kivi_tmp_int {1}
+  \bool_set_true:N \l_kivi_tmp_bool
+  \bool_while_do:Nn \l_kivi_tmp_bool {
+    \file_if_exist:nTF {firma\int_use:N \l_kivi_tmp_int/ident.tex}
+    {
+      \exp_args:Nf \str_if_in:nnTF {#1} {Firma\int_use:N \l_kivi_tmp_int}
+      {
+        \newcommand*{\identpath}{firma\int_use:N \l_kivi_tmpa_int}
+        \bool_set_false:N \l_kivi_tmp_bool
+      }
+      {\int_incr:N \l_kivi_tmp_int}
+    }
+    {
+      \bool_set_false:N \l_kivi_tmp_bool
+      \newcommand*{\identpath}{firma}
+    }
+  }
 }
 
-\newcommand*{\setupCurrencyConfig}[2]{
-       \tl_new:N \g_kivi_currency_tl
-       \exp_args:Nf \str_if_in:nnT {#2} {USD} {\tl_gset:Nn \g_kivi_currency_tl {usd}}
-       \exp_args:Nf \str_if_in:nnT {#2} {CHF} {\tl_gset:Nn \g_kivi_currency_tl {chf}}
-       \exp_args:Nf \str_if_in:nnT {#2} {EUR} {\tl_gset:Nn \g_kivi_currency_tl {euro}}
-       \tl_if_empty:NT  \g_kivi_currency_tl {
-               \tl_gset:Nn \g_kivi_currency_tl {default}
-               \edef \currency {\tl_to_str:N \lxcurrency}
-       }
-       \input{#1/\g_kivi_currency_tl _account.tex}
+\newcommand*{\setupCurrencyConfig}[3][euro]{
+  \tl_new:N \g_kivi_currency_tl
+  \exp_args:Nf \str_if_in:nnT {#3} {USD} {\tl_gset:Nn \g_kivi_currency_tl {usd}}
+  \exp_args:Nf \str_if_in:nnT {#3} {CHF} {\tl_gset:Nn \g_kivi_currency_tl {chf}}
+  \exp_args:Nf \str_if_in:nnT {#3} {EUR} {\tl_gset:Nn \g_kivi_currency_tl {euro}}
+  \tl_if_empty:NT  \g_kivi_currency_tl {
+    \tl_if_empty:oTF {#3} {
+      \tl_gset:Nn \g_kivi_currency_tl {#1}
+    } {
+      \tl_gset:Nn \g_kivi_currency_tl {#3}
+    }
+  }
+  \input{#2/\g_kivi_currency_tl _account.tex}
+  \let\setupCurrencyConfig\_kivi_currency_already_configured:w
 }
 
+\newcommand*{\_kivi_currency_already_configured:w}[3][euro]{
+  \msg_error:nnx {kiviletter} {currency-already-configured} {\g_kivi_currency_tl}
+}
+
+\msg_new:nnn {kiviletter} {currency-already-configured} {
+  The~currency~configuration~is~a~global~setting~for~each~document.\\
+  It's~already~set~to~#1,~please~remove~the~second~call~of~\string\setupCurrencyConfig.
+}
 \ExplSyntaxOff
 
 
 \renewcommand*{\raggedsignature}{\raggedright}
 
 \newkomafont{extraDescription}{}
+\newkomafont{subtotal}{}
+\newkomafont{total}{}
 
 \endinput
index 6e91e74..4e6ed0b 100644 (file)
@@ -7,8 +7,8 @@
 \usepackage{iftex}
 %Compilerunabhängigkeit
 \ifPDFTeX
-       \usepackage[utf8]{inputenc}
-       \usepackage[T1]{fontenc}
+  \usepackage[utf8]{inputenc}
+  \usepackage[T1]{fontenc}
 \fi
 \usepackage{latexsym}
 \usepackage{longtable}
@@ -52,7 +52,7 @@
 \renewcommand*{\familydefault}{\sfdefault}
 \ifPDFTeX
 \else
-\usepackage{fontspec}
+  \usepackage{fontspec}
 \fi
 
 %% Checkboxen
 % Abschnitte mit Kasten hinterlegt
 
 \newcommand{\reqspecsectionstyle}{%
-\renewcommand{\thesection}{\alph{section}}
-\makeatletter
-\def\section{\@ifstar\unnumberedsection\numberedsection}
-\makeatother
+  \renewcommand{\thesection}{\alph{section}}
+  \makeatletter
+  \def\section{\@ifstar\unnumberedsection\numberedsection}
+  \makeatother
 }
 
 \makeatletter
 \def\numberedsection{\@ifnextchar[%]
-  \numberedsectionwithtwoarguments\numberedsectionwithoneargument}
+\numberedsectionwithtwoarguments\numberedsectionwithoneargument}
 \def\unnumberedsection{\@ifnextchar[%]
-  \unnumberedsectionwithtwoarguments\unnumberedsectionwithoneargument}
+\unnumberedsectionwithtwoarguments\unnumberedsectionwithoneargument}
 \def\numberedsectionwithoneargument#1{\numberedsectionwithtwoarguments[#1]{#1}}
 \def\unnumberedsectionwithoneargument#1{\unnumberedsectionwithtwoarguments[#1]{#1}}
 \def\numberedsectionwithtwoarguments[#1]#2{%
   \endgroup
   \vskip 2ex\nobreak
   \addcontentsline{toc}{section}{\protect\numberline{\thesection{}.}#1}%
-  }
+}
 \def\unnumberedsectionwithtwoarguments[#1]#2{%
   \ifhmode\par\fi
   \removelastskip
index 1ea7a2d..1f29b1d 100644 (file)
@@ -34,14 +34,15 @@ $( IF letter.subject )$
 $( END )$
 
 \begin{letter}{
-               $( KiviLatex.filter(customer.name) )$\strut\\
-               $( KiviLatex.filter(letter.contact.formal_greeting) )$\strut\\
-               $( KiviLatex.filter(customer.street) )$\strut\\
-               $( KiviLatex.filter(customer.zipcode) )$ $( KiviLatex.filter(customer.city) )$\strut\\
-               $( KiviLatex.filter(customer.country) )$%
-       }
+$( KiviLatex.filter(customer.name) )$\strut\\
+$( KiviLatex.filter(letter.contact.formal_greeting) )$\strut\\
+$( KiviLatex.filter(customer.street) )$\strut\\
+$( KiviLatex.filter(customer.zipcode) )$ $( KiviLatex.filter(customer.city) )$\strut\\
+$( KiviLatex.filter(customer.country) )$%
+}
 
 \opening{$( KiviLatex.filter(letter.greeting) )$}
+\thispagestyle{kivitendo.letter.first}
 
 $( KiviLatex.filter_html(letter.body) )$
 
index 612fa0c..23736b5 100644 (file)
 \setkomavar{title}{\sammelliste}
 
 \setkomavar{firsthead}{
-       \normalsize
-       \noindent\begin{tabular}[t]{@{}l@{}}
-               <%company%>\strut\\
-               <%address%>
-       \end{tabular}
-       \hfill
- \begin{tabular}[t]{rr@{}}
-               Tel & <%tel%>\\
-               Fax & <%fax%>%
-       \end{tabular}
-       \rule{\linewidth}{\heavyrulewidth}
+  \normalsize
+  \noindent\begin{tabular}[t]{@{}l@{}}
+    <%company%>\strut\\
+    <%address%>
+  \end{tabular}
+  \hfill
 \begin{tabular}[t]{rr@{}}
+    Tel & < %tel%>\\
+    Fax & < %fax%>%
+  \end{tabular}
+  \rule{\linewidth}{\heavyrulewidth}
 }
 
 \makeatletter
 \setkomavar{location}{
-       \normalsize
-       <%shiptocontact%>%
-       <%if shiptophone%>%
-       \\\textTelefon : <%shiptophone%>
-       <%end shiptophone%>%
-       <%if shiptofax%>%
-       \\\textFax : <%shiptofax%>
-       <%end shiptofax%>%
-       \\%
-       <%shiptoemail%>%
-       }
+  \normalsize
+  <%shiptocontact%>%
+  <%if shiptophone%>%
+  \\\textTelefon : <%shiptophone%>
+  <%end shiptophone%>%
+  <%if shiptofax%>%
+  \\\textFax : <%shiptofax%>
+  <%end shiptofax%>%
+  \\%
+  <%shiptoemail%>%
+}
 \makeatother
 
 \setkomavar{backaddress}{\lieferanschrift}
 
 \begin{letter}{\strut%
-       <%shiptoname%>\ifhmode\\\fi
-       <%shiptostreet%>\ifhmode\\\fi
-       <%shiptozipcode%>\ifhmode\\\fi
-       <%shiptocity%>\ifhmode\\\fi
-       <%shiptocountry%>%
+<%shiptoname%>\ifhmode\\\fi
+<%shiptostreet%>\ifhmode\\\fi
+<%shiptozipcode%>\ifhmode\\\fi
+<%shiptocity%>\ifhmode\\\fi
+<%shiptocountry%>%
 }
 
 \opening{}
 
 
 \begin{SimpleTabular}[colspec=*6X,headline={\bfseries\bestellnummer&\bfseries\datum&\bfseries\kontakt
-  <%if warehouse%>%
-  &\bfseries\lager%
-  <%end warehouse%>%
-  &\bfseries\lagerplatz&\bfseries\lieferungMit}]
+        <%if warehouse%>%
+        &\bfseries\lager%
+        <%end warehouse%>%
+        &\bfseries\lagerplatz&\bfseries\lieferungMit}]
   <%ordnumber%>%
   &%
   <%if shippingdate%>%
-       <%shippingdate%>%
+  <%shippingdate%>%
   <%end shippingdate%>%
   <%if not shippingdate%>%
-       <%orddate%>%
+  <%orddate%>%
   <%end shippingdate%>%
   & <%employee%>%
   <%if warehouse%>%
 \bigskip
 
 \begin{SimpleTabular}[colspec=rlXrcll,headline={\bfseries\position&\bfseries\nummer&\bfseries\beschreibung&\bfseries\menge&\bfseries\lagerausgang&&\bfseries\lagerplatz}]%
-<%foreach number%>%
-<%runningnumber%> & <%number%> & <%description%> &%
-<%qty%> & [\hspace{1cm}] & <%unit%> & <%bin%> \\%
-<%end number%>%
+  <%foreach number%>%
+  <%runningnumber%> & <%number%> & <%description%> &%
+  <%qty%> & [\hspace{1cm}] & <%unit%> & <%bin%> \\%
+  <%end number%>%
 \end{SimpleTabular}
 
 \end{letter}
index b5396cd..6730a7e 100644 (file)
 
 
 \begin{document}
-       
+
 \setkomavar{title}{
-       \proformarechnung~
-       \nr ~<%ordnumber%>%
+  \proformarechnung~
+  \nr ~<%ordnumber%>%
 }
 \setkomavar*{date}{\datum}
 
 \setkomavar{date}{<%orddate%>}
 \setkomavar{customer}{<%customernumber%>}
 <%if cusordnumber%>%
-       \setkomavar*{yourref}{\ihreBestellnummer}
-       \setkomavar{yourref}{<%cusordnumber%>}
+\setkomavar*{yourref}{\ihreBestellnummer}
+\setkomavar{yourref}{<%cusordnumber%>}
 <%end if%>%
 <%if quonumber%>\setkomavar{quote}{<%quonumber%>}<%end if%>%
 \setkomavar{fromname}{<%employee_name%>}
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{transaction}{<%transaction_description%>}
-       
+
 <%if shiptoname%>%
 \makeatletter
 \begin{lrbox}\shippingAddressBox
-       \parbox{\useplength{toaddrwidth}}{
-               \backaddr@format{\scriptsize\usekomafont{backaddress}%
-                       \strut\abweichendeLieferadresse
-               }
-               \par\smallskip
-               \setlength{\parskip}{\z@}
-               \par
-               \normalsize
-               <%shiptoname%>\par
-               <%if shiptocontact%> <%shiptocontact%><%end if%>\par
-               <%shiptodepartment_1%>\par
-               <%shiptodepartment_2%>\par
-               <%shiptostreet%>\par
-               <%shiptozipcode%> <%shiptocity%>%
-       }
+  \parbox{\useplength{toaddrwidth}}{
+    \backaddr@format{\scriptsize\usekomafont{backaddress}%
+      \strut\abweichendeLieferadresse
+    }
+    \par\smallskip
+    \setlength{\parskip}{\z@}
+    \par
+    \normalsize
+    <%shiptoname%>\par
+    <%if shiptocontact%> <%shiptocontact%><%end if%>\par
+    <%shiptodepartment_1%>\par
+    <%shiptodepartment_2%>\par
+    <%shiptostreet%>\par
+    <%shiptozipcode%> <%shiptocity%>%
+  }
 \end{lrbox}
 \makeatother
 <%end if%>%
 
 \begin{letter}{
-               <%name%>\strut\\
-               <%if department_1%><%department_1%>\\<%end if%>%
-               <%if department_2%><%department_2%>\\<%end if%>%
-               <%cp_givenname%> <%cp_name%>\strut\\
-               <%street%>\strut\\
-               <%zipcode%> <%city%>\strut\\
-               <%country%> \strut
-       }
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
+}
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-               {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-               {
-                       \Ifstr{<%cp_gender%>}{f}
-                               {\anredefrau}
-                               {\anredeherr}
-                               <%cp_title%> <%cp_name%>,
-                       }
-               }
-               \thispagestyle{kivitendo.letter.first}
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
+\thispagestyle{kivitendo.letter.first}
 
 \auftragsformel
+
 \begin{PricingTabular*}%
-% eigentliche Tabelle
-\FakeTable{%
-       <%foreach number%>%
-       <%runningnumber%> &%
-       <%number%> &%
-       \textbf{<%description%>}%
-       <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
-       <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
-       <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
-       <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
-       <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
-       &%
-       <%qty%> <%unit%> &%
-       <%sellprice%>&%
-       \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
-       <%linetotal%>\tabularnewline%
-       <%end number%>%
-}%
-\begin{PricingTotal}%
-       % Tabellenende letzte Seite%
-       \nettobetrag & <%subtotal%>\\%
-       <%foreach tax%>%
-       <%taxdescription%> & <%tax%>\\%
-       <%end tax%>%
-       \bfseries\schlussbetrag &  \bfseries <%invtotal%>\\%
-\end{PricingTotal}%
+  % eigentliche Tabelle
+  \FakeTable{%
+  <%foreach number%>%
+  <%runningnumber%> &%
+  <%number%> &%
+  \textbf{<%description%>}%
+  <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
+  <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
+  <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
+  <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
+  <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
+  &%
+  <%qty%> <%unit%> &%
+  <%sellprice%>&%
+  \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
+    <%linetotal%>\tabularnewline%
+    <%end number%>%
+  }%
+  \begin{PricingTotal}%
+    % Tabellenende letzte Seite%
+    \nettobetrag & <%subtotal%>\\%
+    <%foreach tax%>%
+    <%taxdescription%> & <%tax%>\\%
+    <%end tax%>%
+    \bfseries\schlussbetrag &  \bfseries <%invtotal%>\\%
+  \end{PricingTotal}%
 \end{PricingTabular*}
 
 <%if notes%>%
index 0748877..ddadec8 100644 (file)
 % settings: Einstellungen, Logo, Briefpapier, Kopfzeile, Fusszeile
 \input{insettings.tex}
 
+<%if template_meta.formname == "supplier_delivery_order"%>
+  \renewcommand{\einkaufslieferschein} {\beistelllieferschein}
+<%end%>
+
 
 % laufende Kopfzeile:
 \ourhead{}{}{\einkaufslieferschein}{<%donumber%>}{<%dodate%>}
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \einkaufslieferschein~\nr ~<%donumber%>%
+  \einkaufslieferschein~\nr ~<%donumber%>%
 }
 <%if ordnumber%>
-       \setkomavar{orderID}{<%ordnumber%>}
+  \setkomavar{orderID}{<%ordnumber%>}
 <%end if%>%
 <%if cusordnumber%>%
-       \setkomavar*{yourref}{\unsereBestellnummer}
-       \setkomavar{yourref}{<%cusordnumber%>}
+  \setkomavar*{yourref}{\unsereBestellnummer}
+  \setkomavar{yourref}{<%cusordnumber%>}
 <%end if%>%
 \setkomavar{transaction}{<%transaction_description%>}
 
 <%if globalprojectnumber%>%
-       \setkomavar{projectID}{<%globalprojectnumber%>}
+  \setkomavar{projectID}{<%globalprojectnumber%>}
 <%end globalprojectnumber%>%
 
 \setkomavar{transaction}{<%transaction_description%>}
 <%if shiptoname%>%
 \makeatletter
 \begin{lrbox}\shippingAddressBox
-       \parbox{\useplength{toaddrwidth}}{
-               \backaddr@format{\scriptsize\usekomafont{backaddress}%
-                       \strut\abweichendeLieferadresse
-               }
-               \par\smallskip
-               \setlength{\parskip}{\z@}
-               \par
-               \normalsize
-               <%shiptoname%>\par
-               <%if shiptocontact%> <%shiptocontact%><%end if%>\par
-               <%shiptodepartment_1%>\par
-               <%shiptodepartment_2%>\par
-               <%shiptostreet%>\par
-               <%shiptozipcode%> <%shiptocity%>%
-       }
+  \parbox{\useplength{toaddrwidth}}{
+    \backaddr@format{\scriptsize\usekomafont{backaddress}%
+      \strut\abweichendeLieferadresse
+    }
+    \par\smallskip
+    \setlength{\parskip}{\z@}
+    \par
+    \normalsize
+    <%shiptoname%>\par
+    <%if shiptocontact%> <%shiptocontact%><%end if%>\par
+    <%shiptodepartment_1%>\par
+    <%shiptodepartment_2%>\par
+    <%shiptostreet%>\par
+    <%shiptozipcode%> <%shiptocity%>%
+  }
 \end{lrbox}
 \makeatother
 <%end if%>%
 
 
 \begin{letter}{
-       <%name%>\strut\\
-       <%if department_1%><%department_1%>\\<%end if%>%
-       <%if department_2%><%department_2%>\\<%end if%>%
-       <%cp_givenname%> <%cp_name%>\strut\\
-       <%street%>\strut\\
-       <%zipcode%> <%city%>\strut\\
-       <%country%> \strut
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
 }
 
 
 \thispagestyle{kivitendo.letter.first}
 
 \begin{PricingTabular*}[columns={pos,amount,desc}]
-% eigentliche Tabelle
-\FakeTable{
-<%foreach number%>%
-       <%runningnumber%> &
-       <%qty%> <%unit%> &
-       \textbf{<%description%>}
-               <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
-               <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
-               <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
-               <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
-               <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
-               <%foreach si_number%>%
-                       <%if si_chargenumber%>\ExtraDescription{\charge: <%si_chargenumber%> <%if si_bestbefore%> \mhd: <%si_bestbefore%><%end if%><%si_qty%>~<%si_unit%><%end si_chargenumber%>}%
-               <%end si_number%>%
-       \tabularnewline
-<%end number%>%
-}
+  % eigentliche Tabelle
+  \FakeTable{
+  <%foreach number%>%
+  <%runningnumber%> &
+  <%qty%> <%unit%> &
+  \textbf{<%description%>}
+    <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
+    <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
+    <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
+    <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
+    <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
+    <%foreach si_number%>%
+    <%if si_chargenumber%>\ExtraDescription{\charge: <%si_chargenumber%> <%if si_bestbefore%> \mhd: <%si_bestbefore%><%end if%><%si_qty%>~<%si_unit%><%end si_chargenumber%>}%
+    <%end si_number%>%
+    \tabularnewline
+    <%end number%>%
+  }
 \end{PricingTabular*}
 
 \medskip
 <%end if%>%
 
 <%if delivery_term%>%
-  \lieferung ~<%delivery_term.description_long%>\\
+\lieferung ~<%delivery_term.description_long%>\\
 <%end delivery_term%>%
 
 \end{letter}
index 677e2ab..9c8d610 100644 (file)
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \bestellung~
-       \nr~<%ordnumber%>%
+  \bestellung~
+  \nr~<%ordnumber%>%
 }
 
 <%if cusordnumber%>%
-       \setkomavar*{yourref}{\unsereBestellnummer}
-       \setkomavar{yourref}{<%cusordnumber%>}
+  \setkomavar*{yourref}{\unsereBestellnummer}
+  \setkomavar{yourref}{<%cusordnumber%>}
 <%end if%>%
 \setkomavar{transaction}{<%transaction_description%>}
 
 <%if quonumber%>
-       \setkomavar{quote}{<%quonumber%>}
+  \setkomavar{quote}{<%quonumber%>}
 <%end if%>%
 
 <%if shiptoname%>%
 \makeatletter
 \begin{lrbox}\shippingAddressBox
-       \parbox{\useplength{toaddrwidth}}{
-               \backaddr@format{\scriptsize\usekomafont{backaddress}%
-                       \strut abweichende Lieferadresse
-               }
-               \par\smallskip
-               \setlength{\parskip}{\z@}
-               \par
-               \normalsize
-               <%shiptoname%>\par
-               <%if shiptocontact%> <%shiptocontact%><%end if%>\par
-               <%shiptodepartment_1%>\par
-               <%shiptodepartment_2%>\par
-               <%shiptostreet%>\par
-               <%shiptozipcode%> <%shiptocity%>%
-       }
+  \parbox{\useplength{toaddrwidth}}{
+    \backaddr@format{\scriptsize\usekomafont{backaddress}%
+      \strut abweichende Lieferadresse
+    }
+    \par\smallskip
+    \setlength{\parskip}{\z@}
+    \par
+    \normalsize
+    <%shiptoname%>\par
+    <%if shiptocontact%> <%shiptocontact%><%end if%>\par
+    <%shiptodepartment_1%>\par
+    <%shiptodepartment_2%>\par
+    <%shiptostreet%>\par
+    <%shiptozipcode%> <%shiptocity%>%
+  }
 \end{lrbox}
 \makeatother
 <%end if%>%
 \begin{document}
 
 \begin{letter}{
-               <%name%>\strut\\
-               <%if department_1%><%department_1%>\\<%end if%>%
-               <%if department_2%><%department_2%>\\<%end if%>%
-               <%cp_givenname%> <%cp_name%>\strut\\
-               <%street%>\strut\\
-               <%zipcode%> <%city%>\strut\\
-               <%country%> \strut
-       }
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
+}
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-       {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-       {
-               \Ifstr{<%cp_gender%>}{f}
-                       {\anredefrau}
-                       {\anredeherr}
-                       <%cp_title%> <%cp_name%>,
-       }
-}
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
 \thispagestyle{kivitendo.letter.first}
 
 \bestellformel
 
 \begin{PricingTabular*}
-       % eigentliche Tabelle
-       \FakeTable{
-       <%foreach number%>%
-               <%runningnumber%> &%
-               <%number%> &%
-               \textbf{<%description%>}%
-               <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
-               <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
-               <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
-               <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
-               <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
-               &%
-               <%qty%> <%unit%> &%
-               <%sellprice%>&%
-               \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
-               <%linetotal%>\tabularnewline
-       <%end number%>%
-       }%
-       \begin{PricingTotal}%
-               % Tabellenende letzte Seite
-               \nettobetrag & <%subtotal%>\\%
-               <%foreach tax%>%
-               <%taxdescription%> & <%tax%>\\%
-               <%end tax%>%
-               \bfseries\schlussbetrag &  \bfseries <%ordtotal%>\\%
-       \end{PricingTotal}
+  % eigentliche Tabelle
+  \FakeTable{
+  <%foreach number%>%
+  <%runningnumber%> &%
+  <%number%> &%
+  \textbf{<%description%>}%
+  <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
+  <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
+  <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
+  <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
+  <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
+  &%
+  <%qty%> <%unit%> &%
+  <%sellprice%>&%
+  \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
+    <%linetotal%>\tabularnewline
+    <%end number%>%
+  }%
+  \begin{PricingTotal}%
+    % Tabellenende letzte Seite
+    \nettobetrag & <%subtotal%>\\%
+    <%foreach tax%>%
+    <%taxdescription%> & <%tax%>\\%
+    <%end tax%>%
+    \bfseries\schlussbetrag &  \bfseries <%ordtotal%>\\%
+  \end{PricingTotal}
 \end{PricingTabular*}
 
 <%if notes%>%
 <%end if%>%
 
 <%if delivery_term%>%
-  \lieferung ~<%delivery_term.description_long%>\\
+\lieferung ~<%delivery_term.description_long%>\\
 <%end delivery_term%>%
 
 \closing{\gruesse}
index 2725140..ad428f7 100644 (file)
 \setplength{firstheadvpos}{4cm}
 
 \setkomavar{firsthead}{
-       \noindent\begin{tabular}[t]{@{}l@{}}
-               <%company%>\strut\\
-               <%address%>
-       \end{tabular}
-       \hfill
-       <%source%>\par
-       \medskip
-       <%text\_amount%> \dotfill <%decimal%>/100 \par\smallskip
-       \hfill <%datepaid%> \hspace{2cm}\strut<%amount%>
+  \noindent\begin{tabular}[t]{@{}l@{}}
+    <%company%>\strut\\
+    <%address%>
+  \end{tabular}
+  \hfill
+  <%source%>\par
+  \medskip
+  <%text\_amount%> \dotfill <%decimal%>/100 \par\smallskip
+  \hfill <%datepaid%> \hspace{2cm}\strut<%amount%>
 }
 
 
 \begin{document}
 
 \begin{letter}{
-               <%name%>\ifhmode\\\fi
-               <%street%>\ifhmode\\\fi
-               <%zipcode%> <%city%>\ifhmode\\\fi
-               <%country%>%
-       }
+<%name%>\ifhmode\\\fi
+<%street%>\ifhmode\\\fi
+<%zipcode%> <%city%>\ifhmode\\\fi
+<%country%>%
+}
 
 \opening{<%company%>}
 \pagestyle{empty}
@@ -43,9 +43,9 @@
 <%name%> \hfill <%datepaid%> \hfill <%source%>%
 
 \begin{SimpleTabular}[colspec=lXrr,headline={\bfseries\rechnung&\bfseries\ausgestellt&\bfseries\faellig&\bfseries\verrechnet}]
-<%foreach invnumber%>%
-<%invnumber%> & <%invdate%> & <%due%> & <%paid%> \\
-<%end invnumber%>%
+  <%foreach invnumber%>%
+  <%invnumber%> & <%invdate%> & <%due%> & <%paid%> \\
+  <%end invnumber%>%
 \end{SimpleTabular}
 
 \end{letter}
index 9631735..0cfc119 100644 (file)
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \anfrage~
-       \nr ~<%quonumber%>%
+  \anfrage~
+  \nr ~<%quonumber%>%
 }
 <%if globalprojectnumber%>%
-       \setkomavar{projectID}{<%globalprojectnumber%>}
+  \setkomavar{projectID}{<%globalprojectnumber%>}
 <%end globalprojectnumber%>%
 
 \setkomavar{transaction}{<%transaction_description%>}
 \begin{document}
 
 \begin{letter}{
-               <%name%>\strut\\
-               <%if department_1%><%department_1%>\\<%end if%>%
-               <%if department_2%><%department_2%>\\<%end if%>%
-               <%cp_givenname%> <%cp_name%>\strut\\
-               <%street%>\strut\\
-               <%zipcode%> <%city%>\strut\\
-               <%country%> \strut
-       }
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
+}
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-               {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-               {
-                       \Ifstr{<%cp_gender%>}{f}
-                               {\anredefrau}
-                               {\anredeherr}
-                               <%cp_title%> <%cp_name%>,
-               }
-}
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
 \thispagestyle{kivitendo.letter.first}
 
 \anfrageformel
 
 \begin{PricingTabular*}[columns={pos,amount,desc}]
-% eigentliche Tabelle
-\FakeTable{
-<%foreach number%>%
-       <%runningnumber%> &
-       <%qty%> <%unit%> &
-       \textbf{<%description%>}
-       <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
-       <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
-       <%if make%>%
-               <%foreach make%>%
-                       \Ifstr{<%make%>}{<%name%>}{\ExtraDescription{\artikelnummer: <%model%>}}{}
-               <%end foreach%>%
-       <%end if%>%
-       \tabularnewline
-<%end number%>%
-}%
+  % eigentliche Tabelle
+  \FakeTable{
+  <%foreach number%>%
+  <%runningnumber%> &
+  <%qty%> <%unit%> &
+  \textbf{<%description%>}
+  <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
+  <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
+  <%if make%>%
+  <%foreach make%>%
+  \Ifstr{<%make%>}{<%name%>}{\ExtraDescription{\artikelnummer: <%model%>}}{}
+    <%end foreach%>%
+    <%end if%>%
+    \tabularnewline
+    <%end number%>%
+  }%
 \end{PricingTabular*}
 
 
@@ -87,7 +87,7 @@
 
 
 <%if delivery_term%>%
-  \lieferung ~<%delivery_term.description_long%>\\
+\lieferung ~<%delivery_term.description_long%>\\
 <%end delivery_term%>%
 
 <%if reqdate%>%
index 1d22e9c..bd08dc6 100644 (file)
@@ -45,10 +45,10 @@ $( KiviLatex.required_packages_for_html )$
       \Large
       $( KiviLatex.filter(rspec.title) )$
       \normalsize
-%$( IF rspec.version )$
+      %$( IF rspec.version )$
 
-    Version $( KiviLatex.filter(rspec.version.version_number) )$
-%$( END )$
+      Version $( KiviLatex.filter(rspec.version.version_number) )$
+      %$( END )$
     \end{minipage}%
   }
 \end{picture}
@@ -59,6 +59,23 @@ $( KiviLatex.required_packages_for_html )$
 
 %\tableofcontents
 
+%%%% Deaktiviertes Beispiel, wie benutzerdefinierte Variablen ausgegeben werden können: %%%%
+%% \newpage
+%%
+%% \section{Benutzerdefinierte Variablen}
+%%
+%% %$ ( FOREACH cvar = rspec.cvars_by_config ) $
+%% Name: $ ( KiviLatex.filter(cvar.config.name) ) $
+%%
+%% Wert:% $ ( IF cvar.config.type == 'htmlfield' ) $
+%% $ ( KiviLatex.filter_html(cvar.value_as_text) ) $
+%% % $ ( ELSE ) $
+%% $ ( KiviLatex.filter(cvar.value_as_text) ) $
+%% % $ ( END ) $
+%%
+%% %$ ( END ) $
+%%%% ENDE Beispiel für benutzerdefinierte Variablen %%%%
+
 %% Versionen
 \newpage
 
@@ -69,19 +86,19 @@ $( KiviLatex.required_packages_for_html )$
 %$( SET working_copy     = rspec.working_copy_id ? rspec.working_copy : rspec )$
 %$( SET versioned_copies = rspec.version ? working_copy.versioned_copies_sorted(max_version_number = rspec.version.version_number) : working_copy.versioned_copies_sorted )$
 %$( IF !versioned_copies.size )$
-  Bisher wurden noch keine Versionen angelegt.
+Bisher wurden noch keine Versionen angelegt.
 %$( ELSE )$
 \begin{longtable}{|p{2cm}|p{2cm}|p{12cm}|}
   \hline
-  \multicolumn{1}{|r}{\small Version} &
-  \multicolumn{1}{|r|}{\small Datum} &
-  \small Beschreibung\\
+  \multicolumn{1}{|r}{\small Version}                                                                                &
+  \multicolumn{1}{|r|}{\small Datum}                                                                                 &
+  \small Beschreibung                                                                                                  \\
   \hline
-%$( FOREACH versioned_copy = versioned_copies )$
-   \multicolumn{1}{|r}{\small $( KiviLatex.filter(versioned_copy.version.version_number) )$} &
-   \multicolumn{1}{|r|}{\small $( KiviLatex.filter(versioned_copy.version.itime.to_kivitendo(precision='minute')) )$} &
-   \small $( KiviLatex.filter(versioned_copy.version.description) )$\\
-%$( END )$
+  %$( FOREACH versioned_copy = versioned_copies )$
+  \multicolumn{1}{|r}{\small $( KiviLatex.filter(versioned_copy.version.version_number) )$}                          &
+  \multicolumn{1}{|r|}{\small $( KiviLatex.filter(versioned_copy.version.itime.to_kivitendo(precision='minute')) )$} &
+  \small $( KiviLatex.filter(versioned_copy.version.description) )$                                                    \\
+  %$( END )$
   \hline
 \end{longtable}
 %$( END )$
@@ -93,7 +110,7 @@ $( KiviLatex.required_packages_for_html )$
   \centering
   \includegraphics[width=$( width_cm )$cm,keepaspectratio]{$( picture.print_file_name )$}
 
-\mbox{Abbildung $( picture.number )$: $( KiviLatex.filter(picture.description ? picture.description : picture.picture_file_name) )$}
+  \mbox{Abbildung $( picture.number )$: $( KiviLatex.filter(picture.description ? picture.description : picture.picture_file_name) )$}
 \end{figure}
 %$( END )$
 
@@ -101,13 +118,13 @@ $( KiviLatex.required_packages_for_html )$
 %  $( SET text_blocks = rspec.text_blocks_sorted(output_position=output_position) )$
 %  $( IF text_blocks.size )$
 
-  \newpage
+\newpage
 
-  \section{$( heading )$}
+\section{$( heading )$}
 
 %    $( FOREACH text_block = text_blocks )$
 
-    \subsection{$( KiviLatex.filter(text_block.title) )$}
+\subsection{$( KiviLatex.filter(text_block.title) )$}
 
 $( KiviLatex.filter_html(text_block.text_as_restricted_html) )$
 
@@ -132,31 +149,31 @@ $( PROCESS text_block_outputter output_position=0 heading='Allgemeines' )$
 
 %$( FOREACH top_item = rspec.sections_sorted )$
 
-  \subsection{Abschnitt $( KiviLatex.filter(top_item.fb_number) )$: $( KiviLatex.filter(top_item.title) )$}
+\subsection{Abschnitt $( KiviLatex.filter(top_item.fb_number) )$: $( KiviLatex.filter(top_item.title) )$}
 
 %  $( IF top_item.description )$
-    $( KiviLatex.filter_html(top_item.description_as_restricted_html.replace('\r', '').replace('\n+\Z', '')) )$
+$( KiviLatex.filter_html(top_item.description_as_restricted_html.replace('\r', '').replace('\n+\Z', '')) )$
 
-    \vspace{0.5cm}
+\vspace{0.5cm}
 %  $( END )$
 %  $( FOREACH item = top_item.children_sorted )$
 \parbox[t]{1.0cm}{\textcolor{kivitendodarkred}{$>>>$}}%
 \parbox[t]{15.0cm}{%
-\begin{longtable}{p{2.8cm}p{11.7cm}}
-  Funktionsblock & $( KiviLatex.filter(item.fb_number) )$\\
-  Beschreibung & $( KiviLatex.filter_html(item.description_as_restricted_html) )$\\
-  Abhängigkeiten & $( KiviLatex.filter(item.presenter.requirement_spec_item_dependency_list) )$
-\end{longtable}}
+  \begin{longtable}{p{2.8cm}p{11.7cm}}
+    Funktionsblock & $( KiviLatex.filter(item.fb_number) )$                                       \\
+    Beschreibung   & $( KiviLatex.filter_html(item.description_as_restricted_html) )$             \\
+    Abhängigkeiten & $( KiviLatex.filter(item.presenter.requirement_spec_item_dependency_list) )$
+  \end{longtable}}
 
 %    $( FOREACH sub_item = item.children_sorted )$
 \hspace*{1.15cm}\rule{15.2cm}{0.2pt}\\
 \hspace*{1.0cm}%
 \parbox[t]{15.0cm}{%
-\begin{longtable}{p{2.8cm}p{11.7cm}}
-  Unterfunktionsblock & $( KiviLatex.filter(sub_item.fb_number) )$\\
-  Beschreibung & $( KiviLatex.filter_html(sub_item.description_as_restricted_html) )$\\
-  Abhängigkeiten & $( KiviLatex.filter(sub_item.presenter.requirement_spec_item_dependency_list) )$
-\end{longtable}}
+  \begin{longtable}{p{2.8cm}p{11.7cm}}
+    Unterfunktionsblock & $( KiviLatex.filter(sub_item.fb_number) )$                                       \\
+    Beschreibung        & $( KiviLatex.filter_html(sub_item.description_as_restricted_html) )$             \\
+    Abhängigkeiten      & $( KiviLatex.filter(sub_item.presenter.requirement_spec_item_dependency_list) )$
+  \end{longtable}}
 
 %    $( END )$
 
index 657abd9..2811e50 100644 (file)
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \lieferschein~
-       \nr~<%donumber%>%
+  \lieferschein~
+  \nr~<%donumber%>%
 }
 <%if ordnumber%>
-       \setkomavar{orderID}{<%ordnumber%>}
+  \setkomavar{orderID}{<%ordnumber%>}
 <%end if%>%
 <%if cusordnumber%>%
-       \setkomavar*{yourref}{\unsereBestellnummer}
-       \setkomavar{yourref}{<%cusordnumber%>}
+  \setkomavar*{yourref}{\unsereBestellnummer}
+  \setkomavar{yourref}{<%cusordnumber%>}
 <%end if%>%
 \setkomavar{transaction}{<%transaction_description%>}
 
 <%if globalprojectnumber%>%
-       \setkomavar{projectID}{<%globalprojectnumber%>}
+  \setkomavar{projectID}{<%globalprojectnumber%>}
 <%end globalprojectnumber%>%
 
 \setkomavar{transaction}{<%transaction_description%>}
 \begin{document}
 
 \begin{letter}{
-  \Ifstr{<%shiptoname%>}{}{ % KEINE ABWEICHENDE LIEFERADRESSE
-       <%name%>\strut\\
-       <%if department_1%><%department_1%>\\<%end if%>%
-       <%if department_2%><%department_2%>\\<%end if%>%
-       <%cp_givenname%> <%cp_name%>\strut\\
-       <%street%>\strut\\
-       <%zipcode%> <%city%>\strut\\
-       <%country%> \strut
-  }{ % ABWEICHENDE LIEFERADRESSE (Aus Stammdaten oder Beleg)
-       <%shiptoname%>\strut\\
-       <%if shiptocontact%> <%shiptocontact%><%end if%>\strut\\
-       <%shiptodepartment_1%>\strut\\
-       <%shiptodepartment_2%>\strut\\
-       <%shiptostreet%>\strut\\
-       <%shiptozipcode%> <%shiptocity%>\strut
-       } % ende ifthenelse LIEFERADRESSE
+\Ifstr{<%shiptoname%>}{}{ % KEINE ABWEICHENDE LIEFERADRESSE
+  <%name%>\strut\\
+  <%if department_1%><%department_1%>\\<%end if%>%
+  <%if department_2%><%department_2%>\\<%end if%>%
+  <%cp_givenname%> <%cp_name%>\strut\\
+  <%street%>\strut\\
+  <%zipcode%> <%city%>\strut\\
+  <%country%> \strut
+}{ % ABWEICHENDE LIEFERADRESSE (Aus Stammdaten oder Beleg)
+  <%shiptoname%>\strut\\
+  <%if shiptocontact%> <%shiptocontact%><%end if%>\strut\\
+  <%shiptodepartment_1%>\strut\\
+  <%shiptodepartment_2%>\strut\\
+  <%shiptostreet%>\strut\\
+  <%shiptozipcode%> <%shiptocity%>\strut
+} % ende ifthenelse LIEFERADRESSE
 }
 
 \opening{}
 \thispagestyle{kivitendo.letter.first}
 
 \begin{PricingTabular*}[columns={pos, id, desc, amount}]
-% eigentliche Tabelle
-\FakeTable{
-<%foreach number%>%
-       <%runningnumber%> &
-       <%number%> &
-       \textbf{<%description%>}
-               <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
-               <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
-               <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
-               <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
-               <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
-               <%foreach si_number%>%
-                       <%if si_chargenumber%>\ExtraDescription{\charge: <%si_chargenumber%> <%if si_bestbefore%> \mhd: <%si_bestbefore%><%end if%><%si_qty%>~<%si_unit%><%end si_chargenumber%>}%
-               <%end si_number%>%
-       &
-               <%qty%> <%unit%>%
-       \tabularnewline
-<%end number%>%
-}
+  % eigentliche Tabelle
+  \FakeTable{
+  <%foreach number%>%
+  <%runningnumber%> &
+  <%number%> &
+  \textbf{<%description%>}
+    <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
+    <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
+    <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
+    <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
+    <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
+    <%foreach si_number%>%
+    <%if si_chargenumber%>\ExtraDescription{\charge: <%si_chargenumber%> <%if si_bestbefore%> \mhd: <%si_bestbefore%><%end if%><%si_qty%>~<%si_unit%><%end si_chargenumber%>}%
+    <%end si_number%>%
+    &
+    <%qty%> <%unit%>%
+    \tabularnewline
+    <%end number%>%
+  }
 \end{PricingTabular*}
 
 \medskip
@@ -94,7 +94,7 @@
 <%end if%>%
 
 <%if delivery_term%>%
-  \lieferung ~<%delivery_term.description_long%>\\
+\lieferung ~<%delivery_term.description_long%>\\
 <%end delivery_term%>%
 
 \end{letter}
index 6bb10c5..e0c8f30 100644 (file)
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \auftragsbestaetigung~
-       \nr~<%ordnumber%>%
+  \auftragsbestaetigung~
+  \nr~<%ordnumber%>%
 }
+<%if tax_point%>%
+  \setkomavar*{taxpoint}{\leistungsdatum}
+  \setkomavar{taxpoint}{<%tax_point%>}
+<%end if%>%
 <%if cusordnumber%>%
-       \setkomavar*{yourref}{\ihreBestellnummer}
-       \setkomavar{yourref}{<%cusordnumber%>}
+  \setkomavar*{yourref}{\ihreBestellnummer}
+  \setkomavar{yourref}{<%cusordnumber%>}
 <%end if%>%
 \setkomavar{transaction}{<%transaction_description%>}
 
 <%if quonumber%>
-       \setkomavar{quote}{<%quonumber%>}
+  \setkomavar{quote}{<%quonumber%>}
 <%end if%>%
 
 <%if shiptoname%>%
 \makeatletter
 \begin{lrbox}\shippingAddressBox
-       \parbox{\useplength{toaddrwidth}}{
-               \backaddr@format{\scriptsize\usekomafont{backaddress}%
-                       \strut abweichende Lieferadresse
-               }
-               \par\smallskip
-               \setlength{\parskip}{\z@}
-               \par
-               \normalsize
-               <%shiptoname%>\par
-               <%if shiptocontact%> <%shiptocontact%><%end if%>\par
-               <%shiptodepartment_1%>\par
-               <%shiptodepartment_2%>\par
-               <%shiptostreet%>\par
-               <%shiptozipcode%> <%shiptocity%>%
-       }
+  \parbox{\useplength{toaddrwidth}}{
+    \backaddr@format{\scriptsize\usekomafont{backaddress}%
+      \strut abweichende Lieferadresse
+    }
+    \par\smallskip
+    \setlength{\parskip}{\z@}
+    \par
+    \normalsize
+    <%shiptoname%>\par
+    <%if shiptocontact%> <%shiptocontact%><%end if%>\par
+    <%shiptodepartment_1%>\par
+    <%shiptodepartment_2%>\par
+    <%shiptostreet%>\par
+    <%shiptozipcode%> <%shiptocity%>%
+  }
 \end{lrbox}
 \makeatother
 <%end if%>%
 \begin{document}
 
 \begin{letter}{
-               <%name%>\strut\\
-               <%if department_1%><%department_1%>\\<%end if%>%
-               <%if department_2%><%department_2%>\\<%end if%>%
-               <%cp_givenname%> <%cp_name%>\strut\\
-               <%street%>\strut\\
-               <%zipcode%> <%city%>\strut\\
-               <%country%> \strut
-       }
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
+}
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-       {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-       {
-               \Ifstr{<%cp_gender%>}{f}
-                       {\anredefrau}
-                       {\anredeherr}
-                       <%cp_title%> <%cp_name%>,
-       }
-}
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
 \thispagestyle{kivitendo.letter.first}
 
 \auftragsformel
 
 \begin{PricingTabular*}
-       % eigentliche Tabelle
-       \FakeTable{
-       <%foreach number%>%
-               <%runningnumber%> &%
-               <%number%> &%
-               \textbf{<%description%>}%
-               <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
-               <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
-               <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
-               <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
-               <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
-               &%
-               <%qty%> <%unit%> &%
-               <%sellprice%>&%
-               \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
-               <%linetotal%>\tabularnewline
-       <%end number%>%
-       }%
-       \begin{PricingTotal}%
-               % Tabellenende letzte Seite
-               \nettobetrag & <%subtotal%>\\%
-               <%foreach tax%>%
-               <%taxdescription%> & <%tax%>\\%
-               <%end tax%>%
-               \bfseries\schlussbetrag &  \bfseries <%ordtotal%>\\%
-       \end{PricingTotal}
+  % eigentliche Tabelle
+  \FakeTable{
+  <%foreach number%>%
+  <%runningnumber%> &%
+  <%number%> &%
+  \textbf{<%description%>}%
+  <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
+  <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
+  <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
+  <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
+  <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
+  &%
+  <%qty%> <%unit%> &%
+  <%sellprice%>&%
+  \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
+    <%linetotal%>\tabularnewline
+    <%end number%>%
+  }%
+  \begin{PricingTotal}%
+    % Tabellenende letzte Seite
+    \nettobetrag & <%subtotal%>\\%
+    <%foreach tax%>%
+    <%taxdescription%> & <%tax%>\\%
+    <%end tax%>%
+    \bfseries\schlussbetrag &  \bfseries <%ordtotal%>\\%
+  \end{PricingTotal}
 \end{PricingTabular*}
 
 <%if notes%>%
 <%end if%>%
 
 <%if delivery_term%>%
-  \lieferung ~<%delivery_term.description_long%>\\
+\lieferung ~<%delivery_term.description_long%>\\
 <%end delivery_term%>%
 
 <%if reqdate%>%
index 0190046..d6e03c8 100644 (file)
@@ -19,9 +19,9 @@
 \begin{document}
 
 \setkomavar{signature}{%
-<%employee_company%>%
-\ifhmode\\\fi
-<%salesman_name%>%
+  <%employee_company%>%
+  \ifhmode\\\fi
+  <%salesman_name%>%
 }
 
 \setkomavar*{date}{\datum}
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \angebot~
-       <%quonumber%>%
+  \angebot~
+  <%quonumber%>%
 }
 
 \setkomavar{transaction}{<%transaction_description%>}
 
 <%if shiptoname%>%
 \makeatletter
-  \begin{lrbox}\shippingAddressBox
+\begin{lrbox}\shippingAddressBox
   \parbox{\useplength{toaddrwidth}}{
-       \backaddr@format{\scriptsize\usekomafont{backaddress}%
-               \strut\abweichendeLieferadresse
-       }
-       \par\smallskip
-       \setlength{\parskip}{\z@}
-       \par
-       \normalsize
-       <%shiptoname%>\par
-        <%if shiptocontact%> <%shiptocontact%><%end if%>\par
-       <%shiptodepartment_1%>\par
-       <%shiptodepartment_2%>\par
-       <%shiptostreet%>\par
-       <%shiptozipcode%> <%shiptocity%>%
- }
+    \backaddr@format{\scriptsize\usekomafont{backaddress}%
+      \strut\abweichendeLieferadresse
+    }
+    \par\smallskip
+    \setlength{\parskip}{\z@}
+    \par
+    \normalsize
+    <%shiptoname%>\par
+    <%if shiptocontact%> <%shiptocontact%><%end if%>\par
+    <%shiptodepartment_1%>\par
+    <%shiptodepartment_2%>\par
+    <%shiptostreet%>\par
+    <%shiptozipcode%> <%shiptocity%>%
 }
 \end{lrbox}
 \makeatother
 <%end if%>%
 
 
 \begin{letter}{
-  <%name%>\strut\\
-  <%if department_1%><%department_1%>\\<%end if%>%
-  <%if department_2%><%department_2%>\\<%end if%>%
-  <%cp_givenname%> <%cp_name%>\strut\\
-  <%street%>\strut\\
-  <%zipcode%> <%city%>\strut\\
-  <%country%> \strut
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
 }
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-               {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-               {
-               \Ifstr{<%cp_gender%>}{f}
-                       {\anredefrau}
-                       {\anredeherr}
-                       <%cp_title%> <%cp_name%>,
-               }
-}
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
 \thispagestyle{kivitendo.letter.first}
 
 \angebotsformel
 
 
 \begin{PricingTabular*}
-% eigentliche Tabelle
-\FakeTable{
-<%foreach number%>%
-<%runningnumber%> &%
-<%number%> &%
-\textbf{<%description%>}%
-       <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
-       <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
-       <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
-       <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
-       <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
-       &%
-       <%qty%> <%unit%> &%
-       <%sellprice%>&%
-       \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
-                       <%linetotal%>\tabularnewline
-<%end number%>%
-}
-       \begin{PricingTotal}
-       % Tabellenende letzte Seite
-       \nettobetrag & <%subtotal%>\\
-       <%foreach tax%>%
-       <%taxdescription%> & <%tax%>\\
-       <%end tax%>%
-       \bfseries\schlussbetrag &  \bfseries <%ordtotal%>\\
-       \end{PricingTotal}
+  % eigentliche Tabelle
+  \FakeTable{
+  <%foreach number%>%
+  <%runningnumber%> &%
+  <%number%> &%
+  \textbf{<%description%>}%
+  <%if longdescription%>\ExtraDescription{<%longdescription%>}<%end longdescription%>%
+  <%if reqdate%>\ExtraDescription{\lieferdatum: <%reqdate%>}<%end reqdate%>%
+  <%if serialnumber%>\ExtraDescription{\seriennummer: <%serialnumber%>}<%end serialnumber%>%
+  <%if ean%>\ExtraDescription{\ean: <%ean%>}<%end ean%>%
+  <%if projectnumber%>\ExtraDescription{\projektnummer: <%projectnumber%>}<%end projectnumber%>%
+  &%
+  <%qty%> <%unit%> &%
+  <%sellprice%>&%
+  \Ifstr{<%p_discount%>}{0}{}{\sffamily\scriptsize{(-<%p_discount%>\,\%)}}%
+    <%linetotal%>\tabularnewline
+    <%end number%>%
+  }
+  \begin{PricingTotal}
+    % Tabellenende letzte Seite
+    \nettobetrag & <%subtotal%>\\
+    <%foreach tax%>%
+    <%taxdescription%> & <%tax%>\\
+    <%end tax%>%
+    \bfseries\schlussbetrag &  \bfseries <%ordtotal%>\\
+  \end{PricingTotal}
 \end{PricingTabular*}
 
 <%if notes%>%
-  <%notes%>%
-  \medskip
+<%notes%>%
+\medskip
 <%end if%>%
 
 <%if delivery_term%>%
-  \lieferung ~<%delivery_term.description_long%>\\
+\lieferung ~<%delivery_term.description_long%>\\
 <%end delivery_term%>%
 
 \angebotdanke\\
 \closing{\gruesse}
 
 \begin{minipage}{\textwidth}
-\rule{\linewidth}{.2pt}\par
-\auftragerteilt\par\bigskip
-\nurort:\rule[-.5ex]{8cm}{.2pt}\ ,\den\ \rule[-.5ex]{5cm}{.2pt}\par\bigskip
+  \rule{\linewidth}{.2pt}\par
+  \auftragerteilt\par\bigskip
+  \nurort:\rule[-.5ex]{8cm}{.2pt}\ ,\den\ \rule[-.5ex]{5cm}{.2pt}\par\bigskip
 
-\unterschrift/\stempel:\rule[-.5ex]{6cm}{.2pt}
+  \unterschrift/\stempel:\rule[-.5ex]{6cm}{.2pt}
 \end{minipage}
 
 
index bfde48e..7cd91a0 100644 (file)
@@ -17,8 +17,8 @@
 
 
 \setkomavar{title}{
-       \sammelrechnung~
-       \nr~<%quonumber%>%
+  \sammelrechnung~
+  \nr~<%quonumber%>%
 }
 \setkomavar{transaction}{<%transaction_description%>}
 \setkomavar{customer}{<%customernumber%>}
 \begin{document}
 
 \begin{letter}{
-               <%name%>\strut\\
-               <%if department_1%><%department_1%>\\<%end if%>%
-               <%if department_2%><%department_2%>\\<%end if%>%
-               <%cp_givenname%> <%cp_name%>\strut\\
-               <%street%>\strut\\
-               <%zipcode%> <%city%>\strut\\
-               <%country%> \strut
-       }
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
+}
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-               {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-               {
-                       \Ifstr{<%cp_gender%>}{f}
-                               {\anredefrau}
-                               {\anredeherr}
-                               <%cp_title%> <%cp_name%>,
-               }
-}
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
 \thispagestyle{kivitendo.letter.first}
 
 \sammelrechnungsformel
 
 \begin{SimpleTabular}[
-       colspec=l*6X,
-       headline={\bfseries\rechnung~\nr & \bfseries\datum & \bfseries\faellig &
-       \bfseries\aktuell & \bfseries\asDreissig & \bfseries\asSechzig & \bfseries\asNeunzig}
-]
-% eigentliche Tabelle
-<%foreach invnumber%>%
-       <%invnumber%> & <%invdate%> & <%duedate%> &
-       <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
-<%end invnumber%>%
-% Tabellenende letzte Seite
-\midrule[\heavyrulewidth]
-\multicolumn{3}{@{}l}{\bfseries\zwischensumme} & \bfseries<%c0total%> & \bfseries<%c30total%> & \bfseries<%c60total%> & \bfseries<%c90total%>\\*
-\midrule
-\multicolumn{3}{@{}l}{\bfseries\schlussbetrag} & &&&\bfseries<%total%> \\
+    colspec=l*6X,
+    headline={\bfseries\rechnung~\nr & \bfseries\datum & \bfseries\faellig &
+        \bfseries\aktuell & \bfseries\asDreissig & \bfseries\asSechzig & \bfseries\asNeunzig}
+  ]
+  % eigentliche Tabelle
+  <%foreach invnumber%>%
+  <%invnumber%> & <%invdate%> & <%duedate%> &
+  <%c0%> & <%c30%> & <%c60%> & <%c90%> \\
+  <%end invnumber%>%
+  % Tabellenende letzte Seite
+  \midrule[\heavyrulewidth]
+  \multicolumn{3}{@{}l}{\bfseries\zwischensumme} & \bfseries<%c0total%> & \bfseries<%c30total%> & \bfseries<%c60total%> & \bfseries<%c90total%>\\*
+  \midrule
+  \multicolumn{3}{@{}l}{\bfseries\schlussbetrag} & &&&\bfseries<%total%> \\
 \end{SimpleTabular}
 
 \closing{\gruesse}
diff --git a/templates/print/marei/supplier_delivery_order.tex b/templates/print/marei/supplier_delivery_order.tex
new file mode 120000 (symlink)
index 0000000..7d185e6
--- /dev/null
@@ -0,0 +1 @@
+purchase_delivery_order.tex
\ No newline at end of file
index 09293ee..abb601f 100644 (file)
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \mahnung
-       <%if dunning_id%>~\nr~<%dunning_id%><%end if%>%
+  \mahnung
+  <%if dunning_id%>~\nr~<%dunning_id%><%end if%>%
 }
 \setkomavar{transaction}{<%transaction_description%>}
 
 \begin{document}
 
 \begin{letter}{
-               <%name%>\strut\\
-               <%if department_1%><%department_1%>\\<%end if%>%
-               <%if department_2%><%department_2%>\\<%end if%>%
-               <%cp_givenname%> <%cp_name%>\strut\\
-               <%street%>\strut\\
-               <%zipcode%> <%city%>\strut\\
-               <%country%> \strut
-       }
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
+}
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-               {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-               {
-                       \Ifstr{<%cp_gender%>}{f}
-                               {\anredefrau}
-                               {\anredeherr}
-                               <%cp_title%> <%cp_name%>,
-               }
-}
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
 \thispagestyle{kivitendo.letter.first}
 
 \mahnungsformel
 
 \begin{SimpleTabular}[headline=\bfseries\rechnung~\nr&\bfseries\datum&\bfseries\betrag,colspec=rXr<{\tabcurrency}]
-% eigentliche Tabelle
-<%foreach dn_invnumber%>%
-    <%dn_invnumber%> & <%dn_transdate%> & <%dn_amount%> \\[0.1cm]
-<%end dn_invnumber%>%
+  % eigentliche Tabelle
+  <%foreach dn_invnumber%>%
+  <%dn_invnumber%> & <%dn_transdate%> & <%dn_amount%> \\[0.1cm]
+  <%end dn_invnumber%>%
 \end{SimpleTabular}
 
 
index da7de4b..9acdeab 100644 (file)
 \setkomavar{fromphone}{<%employee_tel%>}
 \setkomavar{fromemail}{<%employee_email%>}
 \setkomavar{title}{
-       \rechnung~
-       \nr ~<%invnumber%>%
+  \rechnung~
+  \nr ~<%invnumber%>%
 }
 \setkomavar*{myref}{\mahnung~\nr}
 \setkomavar{myref}{<%dunning_id%>}
 <%if globalprojectnumber%>%
-       \setkomavar{projectID}{<%globalprojectnumber%>}
+  \setkomavar{projectID}{<%globalprojectnumber%>}
 <%end globalprojectnumber%>%
 \setkomavar{transaction}{<%transaction_description%>}
 
 
 
 \begin{letter}{
-               <%name%>\strut\\
-               <%if department_1%><%department_1%>\\<%end if%>%
-               <%if department_2%><%department_2%>\\<%end if%>%
-               <%cp_givenname%> <%cp_name%>\strut\\
-               <%street%>\strut\\
-               <%zipcode%> <%city%>\strut\\
-               <%country%> \strut
-       }
+<%name%>\strut\\
+<%if department_1%><%department_1%>\\<%end if%>%
+<%if department_2%><%department_2%>\\<%end if%>%
+<%cp_givenname%> <%cp_name%>\strut\\
+<%street%>\strut\\
+<%zipcode%> <%city%>\strut\\
+<%country%> \strut
+}
 
 % Bei Kontaktperson Anrede nach Geschlecht unterscheiden.
 % Bei natürlichen Personen persönliche Anrede, sonst allgemeine Anrede.
 \opening{
-       \Ifstr{<%cp_name%>}{}
-               {<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
-               {
-                       \Ifstr{<%cp_gender%>}{f}
-                               {\anredefrau}
-                               {\anredeherr}
-                               <%cp_title%> <%cp_name%>,
-               }
-}
+\Ifstr{<%cp_name%>}{}
+{<%if natural_person%><%greeting%> <%name%>,<%else%>\anrede<%end if%>}
+  {
+    \Ifstr{<%cp_gender%>}{f}
+        {\anredefrau}
+        {\anredeherr}
+      <%cp_title%> <%cp_name%>,
+    }
+  }
 \thispagestyle{kivitendo.letter.first}
 
 \mahnungsrechnungsformel
 
 \begin{SimpleTabular}[colspec=Xr<{\tabcurrency},headline={\bfseries\posten& \bfseries\betrag}]
-       Mahngebühren & <%fee%> \\
-       Zinsen & <%interest%> \\
-       \midrule[\heavyrulewidth]
-       \multicolumn{1}{@{}l}{\schlussbetrag}& <%invamount%>\\
+  Mahngebühren & <%fee%> \\
+  Zinsen & <%interest%> \\
+  \midrule[\heavyrulewidth]
+  \multicolumn{1}{@{}l}{\schlussbetrag}& <%invamount%>\\
 \end{SimpleTabular}
 
 \smallskip
diff --git a/templates/print/rev-odt/invoice_qr.odt b/templates/print/rev-odt/invoice_qr.odt
new file mode 100644 (file)
index 0000000..621e478
Binary files /dev/null and b/templates/print/rev-odt/invoice_qr.odt differ
index 1a90d3f..1676be3 100644 (file)
@@ -40,7 +40,7 @@
 
      <tr valign="top">
       <th align="right">[% LxERP.t8('Signature') %]</th>
-      <td>[% L.textarea_tag("user.config_values.signature", props.signature, rows=3, cols=35) %]</td>
+      <td>[% L.textarea_tag("user.config_values.signature", props.signature, rows=3, cols=35, class="texteditor") %]</td>
      </tr>
 
      <tr>
index 6901cba..cd0e7ee 100644 (file)
@@ -1,7 +1,7 @@
 [%- USE T8 %]
 [%- USE LxERP %]
 [%- USE HTML %]
-[%- USE L %]
+[%- USE L %][%- USE P -%]
 
 <h1>[% title %]</h1>
 
      </tr>
 
      <tr>
-      <th align="right">[% 'E-mail' | $T8 %]</th>
+      <th align="right">[% 'Email address' | $T8 %]</th>
       <td><input name="email" size="30" value="[% HTML.escape(MYCONFIG.email) %]"></td>
      </tr>
 
      <tr valign="top">
-      <th align="right">[% 'Signature' | $T8 %]</th>
-      <td><textarea id="signature" name="signature" class="toggletextarea" rows="5" cols="50">[% HTML.escape(MYCONFIG.signature) %] </textarea>
-         <span id="full_signature" class="toggletextarea"> <textarea readonly name="full_signature" rows="10" cols="50" >[% HTML.escape(full_signature) %]</textarea> </span>
-         <a href="#" class="togglelink">[% 'Check full signature' | $T8 %]</a>
-         <a href="#" id="edit_signature" class="togglelink">[% 'Edit user signature' | $T8 %]</a>
-          </td> </tr>
+      <th align="right">[% 'Email signature' | $T8 %]</th>
+      <td>
+       [% P.textarea_tag("signature", MYCONFIG.signature, class="texteditor", rows="5", cols="50") %]
+      </td>
+     </tr>
+
+     <tr valign="top">
+      <th align="right">[% "Company's email signature" | $T8 %]</th>
+      <td>[% P.restricted_html(company_signature) %]</td>
+     </tr>
+
      <tr>
       <th align="right">[% 'Phone' | $T8 %]</th>
       <td><input name="tel" size="14" value="[% HTML.escape(MYCONFIG.tel) %]"></td>
       </td>
      </tr>
 
+     <tr>
+      <th align="right">[% 'Longdescription dialog size percentage from main window (0 means fix values)' | $T8 %]</th>
+      <td>
+        [% L.input_tag('longdescription_dialog_size_percentage', longdescription_dialog_size_percentage, size = 5) %]
+      </td>
+     </tr>
      [%- IF INSTANCE_CONF.get_feature_experimental_order -%]
      <tr>
       <th align="right">[% 'Scrollbar height percentage for form postion area (0 means no scrollbar)' | $T8 %]</th>
    </div>
   </div>
  </form>
-
- <script type="text/javascript">
-  <!--
-$(function() {
-  $("#full_signature").toggle();
-  $("#edit_signature").toggle();
-  $('.togglelink').click(function() {
-    $('.toggletextarea').toggle();
-    $('.togglelink').toggle();
-    return false;
-  });
-});
-    -->
- </script>
index 880106a..e269b8e 100644 (file)
@@ -19,6 +19,9 @@
 [%- ELSIF var.type == 'textfield' %]
 <textarea name="[% var_name %]" cols="[% HTML.escape(var.width) %]" rows="[% HTML.escape(var.height) %]">[% HTML.escape(var.value) %]</textarea>
 
+[%- ELSIF var.type == 'htmlfield' %]
+<textarea name="[% var_name %]" cols="[% HTML.escape(var.width) %]" rows="[% HTML.escape(var.height) %]" class="texteditor">[% HTML.escape(var.value) %]</textarea>
+
 [%- ELSIF var.type == 'date' %]
 [% L.date_tag(var_name, var.value) %]
 
index 7373162..984c589 100644 (file)
 [% render_cvar_tag_options.import(cols=cvar.var.width, rows=cvar.var.height);
    L.textarea_tag(cvar_tag_name, cvar.value, render_cvar_tag_options) %]
 
+[%- ELSIF cvar.var.type == 'htmlfield' %]
+[% render_cvar_tag_options.import(cols=cvar.var.width, rows=cvar.var.height, class="texteditor");
+   L.textarea_tag(cvar_tag_name, L.restricted_html(cvar.value), render_cvar_tag_options) %]
+
 [%- ELSIF cvar.var.type == 'date' %]
 [%- L.date_tag(cvar_tag_name, cvar.value, render_cvar_tag_options) %]
 
index f3aa55e..e3bc2e9 100644 (file)
@@ -89,7 +89,7 @@
               <tr>
                 <th align="right" nowrap>[% 'Vendor' | $T8 %]</th>
                 <td colspan="3">
-                 [% P.customer_vendor.picker("vendor_id", vendor_id, type="vendor", style="width: 300px", onchange="\$('#update_button').click()") %]
+                 [% P.customer_vendor.picker("vendor_id", vendor_id, type="vendor", style="width: 330px", onchange="\$('#update_button').click()") %]
                  [% L.button_tag("show_vc_details('vendor')", LxERP.t8('Details (one letter abbreviation)')) %]
                  [% L.hidden_tag("previous_vendor_id", vendor_id) %]
                 </td>
               [% IF ALL_DEPARTMENTS %]
                 <tr>
                   <th align="right" nowrap>[% 'Department' | $T8 %]</th>
-                  <td colspan=3>[% L.select_tag('department_id', ALL_DEPARTMENTS, default = department_id, title_key = 'description', with_empty = 1) %]</td>
+                  <td colspan=3>[% L.select_tag('department_id', ALL_DEPARTMENTS, default = department_id, title_key = 'description', with_empty = 1, style = "width:334px") %]</td>
                 </tr>
               [% END %]
 
+              <tr>
+                <th align="right">[% 'Transaction description' | $T8 %]</th>
+                <td colspan="3">[% L.input_tag("transaction_description", transaction_description, style="width:330px", "data-validate"=INSTANCE_CONF.get_require_transaction_description_ps ? 'required' : '') %]</td>
+              </tr>
               <tr>
                 <td align="right"><input name="taxincluded" class="checkbox" type="checkbox" value="1" [% IF ( taxincluded ) %]checked[% END %]></td>
                 <th align=left nowrap>[% 'Tax Included' | $T8 %]</th>
               <input name="amount_[% i %]" size="10" value="[% temp = "amount_"_ i %][% $temp | html %]">
             </td>
             <td>
-              [% temp = "tax_"_ i %][% $temp | html %]
+              [% temp_r = "tax_reverse_"_ i %]
+              [% IF ($temp_r) %]
+                [% $temp_r | html %]
+                &nbsp;&nbsp;&nbsp;
+                [% temp_c = "tax_charge_"_ i %][% $temp_c | html %]
+              [% ELSE %]
+                [% temp = "tax_"_ i %][% $temp | html %]
+              [% END %]
             </td>
             <td>
               [% temp = 'selected_taxchart_'_ i %]
 <hr size="3" noshade>
 
 <script type='text/javascript'>
- $('#ap_set_to_paid_missing').click(function(){ $('input[id^="payment_paid_"]:last').val('[% LxERP.format_amount(paid_missing, 2) %]') });
+ $('#ap_set_to_paid_missing').click(function(){ $('input[id^="payment_paid_"]:last').val("[% LxERP.format_amount(paid_missing, 2) %]") });
 </script>
index 59f4b37..a676eb8 100644 (file)
@@ -4,6 +4,7 @@
 <h1>[% title %]</h1>
 
  <form method="post" name="search" action="ap.pl" id="form">
+  [% L.hidden_tag("sort", "transdate") %]
 
   <table width=100%>
   <tr>
       <th align=right nowrap>[% 'Order Number' | $T8 %]</th>
       <td>[% L.input_tag("ordnumber", "", style=style) %]</td>
      </tr>
+     <tr>
+      <th align="right">[% 'Steuersatz' | $T8 %]</th>
+      <td>[% L.select_tag('taxzone_id', ALL_TAXZONES, with_empty=1, title_key='description', style=style) %]</td>
+     </tr>
      <tr>
       <th align="right" nowrap>[% 'Transaction description' | $T8 %]</th>
       <td>[% L.input_tag("transaction_description", "", style=style) %]</td>
@@ -60,7 +65,6 @@
        [% L.date_tag('duedateto') %]
      </td>
     </tr>
-   <input type=hidden name=sort value=transdate>
    </table>
     </td>
     </tr>
            <td nowrap>[% 'Insert Date' | $T8 %]</td>
           </tr>
          <tr>
-          <td colspan=4 align=left><b>[% 'Vendor' | $T8 %] </td>
+          <td colspan=4 align=left><b>[% 'Vendor' | $T8 %]</b></td>
          </tr>
          <tr>
            <td align=right><input name="l_vendornumber" class=checkbox type=checkbox value=Y></td>
index 755d564..d42d70c 100644 (file)
@@ -47,7 +47,7 @@
               <tr>
                 <th align="right" nowrap>[% 'Customer' | $T8 %]</th>
                 <td colspan=3>
-                 [% P.customer_vendor.picker("customer_id", customer_id, type="customer", style="width: 300px", class=(initial_focus == 'customer_id' ? "initial_focus" : ""), onchange="\$('#update_button').click()") %]
+                 [% P.customer_vendor.picker("customer_id", customer_id, type="customer", style="width: 330px", class=(initial_focus == 'customer_id' ? "initial_focus" : ""), onchange="\$('#update_button').click()") %]
                  [% L.button_tag("show_vc_details('customer')", LxERP.t8('Details (one letter abbreviation)')) %]
                  [% L.hidden_tag("previous_customer_id", customer_id) %]
                  [% L.hidden_tag('terms', terms) %]
               [% IF ALL_DEPARTMENTS %]
                 <tr>
                   <th align="right" nowrap>[% 'Department' | $T8 %]</th>
-                  <td colspan=3>[% L.select_tag('department_id', ALL_DEPARTMENTS, default = department_id, title_key = 'description', with_empty = 1) %]</td>
+                  <td colspan=3>[% L.select_tag('department_id', ALL_DEPARTMENTS, default = department_id, title_key = 'description', with_empty = 1, style = 'width:334px') %]</td>
                 </tr>
               [% END %]
+              <tr>
+                <th align="right">[% 'Transaction description' | $T8 %]</th>
+                <td colspan="3">[% L.input_tag("transaction_description", transaction_description, style="width:330px", "data-validate"=INSTANCE_CONF.get_require_transaction_description_ps ? 'required' : '') %]</td>
+              </tr>
               <tr>
                 <td align=right>[% L.checkbox_tag('taxincluded', checked=taxincluded) %]</td>
                 <th align="left" nowrap><label for="taxincluded">[% 'Tax Included' | $T8 %]</label></th>
 </div>
 
 <script type='text/javascript'>
- $('#ar_set_to_paid_missing').click(function(){ $('input[name^="paid_"]:last').val('[% LxERP.format_amount(paid_missing, 2) %]') });
+ $('#ar_set_to_paid_missing').click(function(){ $('input[name^="paid_"]:last').val("[% LxERP.format_amount(paid_missing, 2) %]") });
 </script>
index 4f03f6a..3a68962 100644 (file)
@@ -5,6 +5,7 @@
 
  <form method=post name="search" id="form" action=[% script %]>
   [% L.hidden_tag("action", nextsub) %]
+  [% L.hidden_tag("sort", "transdate") %]
 
   <table width=100% border="0">
   <tr>
      <th align="right">[% 'Salesman' | $T8 %]</th>
      <td>[% L.select_tag('salesman_id', ALL_EMPLOYEES, title_key = 'safe_name', with_empty = 1, style=style) %]</td>
      </tr>
+     <tr>
+      <th align="right">[% 'Steuersatz' | $T8 %]</th>
+      <td>[% L.select_tag('taxzone_id', ALL_TAXZONES, with_empty=1, title_key='description', style=style) %]</td>
+     </tr>
      <tr>
       <th align=right nowrap>[% 'Transaction description' | $T8 %]</th>
       <td>[% L.input_tag("transaction_description", "", style=style) %]</td>
       <th align="right">[% 'Part Number' | $T8 %]</th>
       <td>[% L.input_tag("parts_partnumber", "", style=style) %]</td>
      </tr>
+     <tr>
+      <th align=right nowrap>[% 'Shipping Point' | $T8 %]</th>
+      <td>[% L.input_tag("shippingpoint", "", style=style) %]</td>
+      <th align="right">[% 'Ship via' | $T8 %]</th>
+      <td>[% L.input_tag("shipvia", "", style=style) %]</td>
+     </tr>
      <tr>
       <th align="right">[% 'Project Number' | $T8 %]</th>
       <td>[% P.project.picker("project_id", project_id, active="both", valid="both", style=style) %]</td>
 [%- IF CT_CUSTOM_VARIABLES.size %]
     <tr>
       <td></td>
-      <td colspan=4 align=left><b>[% 'Custom variables for module' | $T8 %]: [%'Customers and vendors' | $T8 %]</td>
+      <td colspan=4 align=left><b>[% 'Custom variables for module' | $T8 %]: [%'Customers and vendors' | $T8 %]</b></td>
     </tr>
     [% CT_CUSTOM_VARIABLES_FILTER_CODE %]
 [%- END %]
 
-   <input type=hidden name=sort value=transdate>
    </table>
     </td>
     </tr>
            <td align=right><input name="l_direct_debit" id="l_direct_debit" class=checkbox type=checkbox value=Y></td>
            <td nowrap>[% 'direct debit' | $T8 %]</td>
           </tr>
+[% IF INSTANCE_CONF.get_doc_storage -%]
+          <tr>
+           <td align=right><input name="l_attachments" id="l_attachments" class=checkbox type=checkbox value=Y></td>
+           <td nowrap>[% 'Attachments' | $T8 %]</td>
+          </tr>
+[% END-%]
           <tr>
-           <td colspan=4 align=left><b>[% 'Customer' | $T8 %] </td>
+           <td colspan=4 align=left><b>[% 'Customer' | $T8 %]</b></td>
           </tr>
           <tr>
            <td align=right><input name="l_customernumber" id="l_customernumber" class=checkbox type=checkbox value=Y></td>
index 45b1818..2af7755 100644 (file)
@@ -1,6 +1,6 @@
 [%- USE HTML %][%- USE L %][%- USE LxERP %][%- USE P -%]
 
-  <b>Transaction</b>
+  <b>[% LxERP.t8("Bank transaction") %]</b>
   <table>
    <tr class="listheading">
     <td>[%- LxERP.t8("ID") %]:</td>
index 964790c..c0392c2 100644 (file)
@@ -4,7 +4,7 @@
 [% USE LxERP %]
 <h1>[% title | html %]</h1>
 
-<form method=post action="[% script %]">
+<form method=post action="[% script | html %]">
 
 [% L.hidden_tag('accno', accno) %]
 [% L.hidden_tag('description', description) %]
index 35a8a3a..05f4e9e 100644 (file)
    <td>[% P.chart.picker('defaults.ar_chart_id', SELF.defaults.ar_chart_id, type='AR', choose=1, style=style) %]<td>
   </tr>
 
+  <tr>
+   <td align="right">[% LxERP.t8("Clearing account for advance payments") %]</td>
+   <td>[% P.chart.picker('defaults.advance_payment_clearing_chart_id', SELF.defaults.advance_payment_clearing_chart_id, choose=1, style=style) %]<td>
+  </tr>
+
   <tr>
    <td align="right">[% LxERP.t8("Account for workflow from purchase order to ap transaction") %]</td>
    <td>[% P.chart.picker('defaults.workflow_po_ap_chart_id', SELF.defaults.workflow_po_ap_chart_id, type='AP_amount', choose=1, style=style) %]<td>
index fe22a7d..cd6aee2 100644 (file)
    <td>   [% L.yes_no_tag('defaults.normalize_part_descriptions', SELF.defaults.normalize_part_descriptions) %]</td>
    <td>[% LxERP.t8('Automatic deletion of leading, trailing and excessive (repetitive) spaces in part description and part notes. Affects the CSV import as well.') %]</td>
  </tr>
+ <tr>
+   <td align="right">[% LxERP.t8('Partsgroup is required for parts') %]</td>
+   <td>   [% L.yes_no_tag('defaults.partsgroup_required', SELF.defaults.partsgroup_required) %]</td>
+   <td>[% LxERP.t8('If enabled, when saving parts the partsgroup must be not be empty.') %]</td>
+ </tr>
 
   <tr><td class="listheading" colspan="4">[% LxERP.t8("Purchasing & Sales") %]</td></tr>
 
    <td>[% L.yes_no_tag("defaults.order_warn_no_deliverydate", SELF.defaults.order_warn_no_deliverydate) %]</td>
    <td>[% LxERP.t8("If enabled a warning will be shown in sales and purchase orders if there the delivery date is empty.") %]</td>
   </tr>
+  <tr>
+   <td align="right">[% LxERP.t8("Warn before saving sales orders with missing customer order number (new controller only)") %]</td>
+   <td>[% L.yes_no_tag("defaults.order_warn_no_cusordnumber", SELF.defaults.order_warn_no_cusordnumber) %]</td>
+   <td>[% LxERP.t8("If enabled a warning will be shown in sales delivery orders if the customer order number is missing.") %]</td>
+  </tr>
   <tr>
    <td align="right">[% LxERP.t8("For sales delivery orders, warn on workflow to invoice if not stocked out") %]</td>
    <td>[% L.yes_no_tag("defaults.sales_delivery_order_check_stocked", SELF.defaults.sales_delivery_order_check_stocked) %]</td>
    <td>[% LxERP.t8("If enabled a warning will be shown in sales delivery orders on workflow to invoices if positions are not stocked out.") %]</td>
   </tr>
-  <tr>
   <tr>
    <td align="right">[% LxERP.t8("For purchase delivery orders, warn on workflow to invoice if not stocked in") %]</td>
    <td>[% L.yes_no_tag("defaults.purchase_delivery_order_check_stocked", SELF.defaults.purchase_delivery_order_check_stocked) %]</td>
    <td>[% LxERP.t8("If enabled a warning will be shown in purchase delivery orders on workflow to invoices if positions are not stocked in.") %]</td>
   </tr>
   <tr>
+   <td align="right">[% LxERP.t8("For sales invoices, warn if invoice has no delivery order as a predecessor") %]</td>
+   <td>[% L.yes_no_tag("defaults.warn_no_delivery_order_for_invoice", SELF.defaults.warn_no_delivery_order_for_invoice ) %]</td>
+   <td>[% LxERP.t8("If enabled a warning will be shown if a sales invoices is created without having a sales delivery order as a predecessor.") %]</td>
+  </tr>
   <tr>
    <td align="right">[% LxERP.t8("Create sales invoices with Factur-X/ZUGFeRD data") %]</td>
    <td>[% L.select_tag("defaults.create_zugferd_invoices", SELF.zugferd_settings, default=SELF.defaults.create_zugferd_invoices) %]</td>
      [% LxERP.t8("If the test mode is enabled, the Factur-X/ZUGFeRD invoices will be flagged so that they're only fit to be used for testing purposes.") %]
    </td>
   </tr>
+  <tr>
+   <td align="right">[% LxERP.t8("Create sales invoices with Swiss QR-bill") %]</td>
+   <td>
+     [% L.select_tag("defaults.create_qrbill_invoices", [ [ 0, LxERP.t8('Do not create QR-bill invoices') ], [ 1, LxERP.t8('Create variant QR-IBAN with QR reference') ], [ 2, LxERP.t8('Create variant IBAN without reference') ] ], default=SELF.defaults.create_qrbill_invoices) %]
+   </td>
+   <td>[% LxERP.t8("If enabled sales invoices created using OpenDocument/OASIS format will include data for Swiss QR-Bill creation.") %]</td>
+  </tr>
+  <tr>
+   <td align="right">[% LxERP.t8("Prevent browser's back button in sales invoices") %]</td>
+   <td>[% L.yes_no_tag("defaults.invoice_prevent_browser_back", SELF.defaults.invoice_prevent_browser_back) %]</td>
+   <td>[% LxERP.t8("If enabled try to overrule the brower's back button to prevent double booking of sales invoices.") %]</td>
+  </tr>
 
   <tr><td class="listheading" colspan="4">[% LxERP.t8("E-mail") %]</td></tr>
 
index f938f72..752bcd8 100644 (file)
@@ -36,7 +36,7 @@
 
   <tr>
    <td align="right" valign="top">[% LxERP.t8("Signature") %]</td>
-   <td valign="top">[% L.textarea_tag('defaults.signature', SELF.defaults.signature, style=style, rows=4) %]</td>
+   <td valign="top">[% L.textarea_tag('defaults.signature', SELF.defaults.signature, style=style, rows=4, class='texteditor') %]</td>
   </tr>
 
   <tr>
    </td>
   </tr>
 
+  <tr>
+   <td align="right">[% LxERP.t8('Interpolate variables in texts of positions') %]</td>
+   <td>[% L.yes_no_tag('defaults.print_interpolate_variables_in_positions', SELF.defaults.print_interpolate_variables_in_positions) %]</td>
+   <td>[% LxERP.t8('Whether or not to replace variable placeholders such as "<%invdate%>" in texts in positions such as the part description by the record\'s actual value') %]</td>
+  </tr>
+
   <tr><td class="listheading" colspan="4">[% LxERP.t8("Currencies") %]</td></tr>
 
   <tr>
index a481639..0235cc3 100644 (file)
    <td>[% L.select_tag('defaults.payments_changeable', SELF.payment_options, value_key = 'value', title_key = 'title', default = SELF.defaults.payments_changeable) %]</td>
    <td>[% LxERP.t8('Should payments be and when should they be changeable after posting?') %]</td>
   </tr>
+  <tr>
+   <td align="right">[% LxERP.t8('Record numbers changeable') %]</td>
+   <td>[% L.yes_no_tag('defaults.sales_purchase_record_numbers_changeable', SELF.defaults.sales_purchase_record_numbers_changeable) %]</td>
+   <td>[% LxERP.t8('If disabled, record numbers for sales records & purchase records produced by our side will always be auto-generated and cannot be changed later.') %]</td>
+  </tr>
 
   <tr> </tr>
   <tr> </tr>
diff --git a/templates/webpages/client_config/_record_links.html b/templates/webpages/client_config/_record_links.html
new file mode 100644 (file)
index 0000000..5dd49f6
--- /dev/null
@@ -0,0 +1,12 @@
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%]
+<div id="record_links">
+ <table>
+  <tr>
+   <td align="right" nowrap="true">[% LxERP.t8('View record links from Sales Order') %]</td>
+   <td>[% L.yes_no_tag('defaults.always_record_links_from_order', SELF.defaults.always_record_links_from_order) %]</td>
+   <td>
+    [% LxERP.t8('If enabled the record links view starts always from the sales order including all sublevels') %]<br>
+   </td>
+  </tr>
+ </table>
+</div>
index dcb5576..79c2cdd 100644 (file)
@@ -93,6 +93,7 @@ $(function() {
    <li><a href="#warehouse">[% LxERP.t8('Warehouse') %]</a></li>
    <li><a href="#features">[% LxERP.t8('Features') %]</a></li>
    <li><a href="#stocktaking">[% LxERP.t8('Stocktaking') %]</a></li>
+   <li><a href="#record_links">[% LxERP.t8('Linked Records') %]</a></li>
   </ul>
 
 [% PROCESS 'client_config/_ranges_of_numbers.html' %]
@@ -106,6 +107,7 @@ $(function() {
 [% PROCESS 'client_config/_warehouse.html' %]
 [% PROCESS 'client_config/_features.html' %]
 [% PROCESS 'client_config/_stocktaking.html' %]
+[% PROCESS 'client_config/_record_links.html' %]
 [% PROCESS 'client_config/_miscellaneous.html' %]
  </div>
 </form>
index 79b984c..487943c 100644 (file)
    </td>
   </tr>
 
+  [%- IF ALL_PARTNER_EMAIL_ADDRESSES.size %]
+   [%- FOREACH email = ALL_PARTNER_EMAIL_ADDRESSES %]
+    <tr class="hidden" data-toggle-recipients="1">
+     <th align="right" nowrap>
+      [%- IF loop.first %]
+       [% LxERP.t8("Other recipients") %]
+      [%- END %]
+     </th>
+     <td>
+       [% P.checkbox_tag("email_form.additional_to[]", label=email, value=email, checked="0") %]
+     </td>
+    </tr>
+   [%- END %]
+  [%- END %]
+
  [%- IF ALL_EMPLOYEES.size %]
   <tr class="hidden" data-toggle-recipients="1">
    <th align="right" nowrap>[% LxERP.t8("CC to Employee") %]</th>
-   <td>[% L.select_tag('email_form.cc_employee',  ALL_EMPLOYEES, value_key='login' title_key='safe_name', with_empty=1, style=style) %]</td>
+   <td>[% L.select_tag('email_form.cc_employee', ALL_EMPLOYEES, value_key='login' title_key='safe_name', with_empty=1, style=style) %]</td>
   </tr>
  [%- END %]
 
@@ -68,7 +83,7 @@
    <th align="right" nowrap>[% LxERP.t8("Message") %]
     <sup> [% L.link("generictranslations.pl?action=edit_email_strings", "1)", title=LxERP.t8('Tired of copying always nice phrases for this message? Click here to use the new preset message option!'), target="_blank") %]</sup>
   </th>
-   <td>[% L.textarea_tag("email_form.message", email_form.message, rows="15" cols="80" wrap="soft") %]</td>
+   <td>[% L.textarea_tag("email_form.message", email_form.message, rows="15", cols="80", class="texteditor texteditor-space-for-toolbar") %]</td>
   </tr>
 
 [% IF INSTANCE_CONF.get_doc_storage %]
@@ -77,8 +92,8 @@
    <td>
     [% SET no_file_label = have_files ? LxERP.t8("Don't include a printout of the record with the email, only selected files") : LxERP.t8("Don't include a printout of the record with the email") ;
            options       = [
+             [ "old_file", LxERP.t8("Send the last or create the first version for this record") ],
              [ "normal",   LxERP.t8("Create and send a new printout for this record") ],
-             [ "old_file", LxERP.t8("Send the last printout created for this record") ],
              [ "no_file",  no_file_label ],
            ] ;
        L.select_tag("email_form.attachment_policy", options, onchange="kivi.SalesPurchase.activate_send_email_actions_regarding_printout()") %]
index d400371..2db49e8 100644 (file)
@@ -5,6 +5,7 @@
 [%- USE LxERP %]
 
 [%- DEFAULT var_name = HTML.escape(cvar_name_prefix) _ HTML.escape(var.config.name) _ HTML.escape(cvar_name_postfix) %]
+[%- SET style_ = "width: " _ var.config.processed_options.WIDTH _ "px; height: " _ var.config.processed_options.HEIGHT _ "px" %]
 
 [%- IF ( hide_non_editable && !var.config.is_flag('editable') ) %]
   [% L.hidden_tag(var_name, var.value) %]
@@ -15,7 +16,9 @@
 [%- ELSIF ( var.config .type == 'bool' ) %]
   [% L.checkbox_tag(var_name, checked = var.value, for_submit = 1) %]
 [%- ELSIF ( var.config .type == 'textfield' ) %]
-  [% L.textarea_tag(var_name, var.value, cols = var.config.processed_options.WIDTH, rows = var.config.processed_options.HEIGHT) %]
+  [% L.textarea_tag(var_name, var.value, style=style_) %]
+[%- ELSIF ( var.config .type == 'htmlfield' ) %]
+  [% L.textarea_tag(var_name, L.restricted_html(var.value), class='texteditor', style=style_) %]
 [%- ELSIF ( var.config.type == 'date' ) %]
   [% L.date_tag(var_name, var.value) %]
 [%- ELSIF ( var.config.type == 'timestamp' ) %]
index f374980..cd9d4b3 100644 (file)
@@ -1,11 +1,18 @@
 [%- USE T8 %]
-[% USE HTML %]
+[% USE HTML %][%- USE LxERP -%]
 <h1>[% IF is_customer %][% 'Customer details' | $T8 %][% ELSE %][% 'Vendor details' | $T8 %][% END %] &quot;[% HTML.escape(name) %]&quot;</h1>
 
 [% BLOCK jump_block %]
 [%- IF SHIPTO.size || CONTACTS.size %]
  <p>
   [% 'Jump to' | $T8 %] <a href="#billing">[% 'Billing Address' | $T8 %]</a>
+  [%- FOREACH additional_billing_addresses = ADDITIONAL_BILLING_ADDRESSES %]
+   ,
+   <a href="#additional_billing_address[% loop.count %]">
+    [% 'Additional Billing Address' | $T8 %]
+    "[% HTML.escape(additional_billing_addresses.name) %]"
+   </a>
+  [%- END %]
   [%- FOREACH shipto = SHIPTO %]
    ,
    <a href="#shipping[% loop.count %]">
@@ -26,7 +33,7 @@
 [%- END %]
 [% END %]
 
- [%- INCLUDE jump_block CONTACTS = CONTACTS, SHIPTO = SHIPTO %]
+ [%- INCLUDE jump_block CONTACTS = CONTACTS, SHIPTO = SHIPTO, ADDITIONAL_BILLING_ADDRESSES = ADDITIONAL_BILLING_ADDRESSES %]
 
  <a name="billing"><h1>[% 'Billing Address' | $T8 %]</h1></a>
 
  </table>
 
 
+ [% FOREACH row = ADDITIONAL_BILLING_ADDRESSES %]
+
+  <hr>
+
+  [%- INCLUDE jump_block CONTACTS = CONTACTS, SHIPTO = SHIPTO, ADDITIONAL_BILLING_ADDRESSES = ADDITIONAL_BILLING_ADDRESSES %]
+
+  <a name="additional_billing_address[% loop.count %]"><h1>[% 'Additional Billing Address' | $T8 %] "[% HTML.escape(row.name) %]"</h1></a>
+
+  <table>
+   <tr>
+    <td align="right">[% 'Default Billing Address' | $T8 %]</td>
+    <td>[% row.default_address ? LxERP.t8('yes') : LxERP.t8('no') %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Name' | $T8 %]</td>
+    <td>[% HTML.escape(row.name) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Department' | $T8 %]</td>
+    <td>[% HTML.escape(row.department_1) %][% IF row.department_2 %][% IF row.department_1 %]; [% END %][% HTML.escape(row.department_2) %][% END %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Street' | $T8 %]</td>
+    <td>[% HTML.escape(row.street) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Zip, City' | $T8 %]</td>
+    <td>[% HTML.escape(row.zipcode) %] [% HTML.escape(row.city) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Country' | $T8 %]</td>
+    <td>[% HTML.escape(row.country) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'GLN' | $T8 %]</td>
+    <td>[% HTML.escape(row.gln) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Contact' | $T8 %]</td>
+    <td>[% HTML.escape(row.contact) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Phone' | $T8 %]</td>
+    <td>[% HTML.escape(row.phone) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Fax' | $T8 %]</td>
+    <td>[% HTML.escape(row.fax) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'E-mail' | $T8 %]</td>
+    <td>[% HTML.escape(row.email) %]</td>
+   </tr>
+
+  </table>
+ [% END %]
 
 
  [% FOREACH row = SHIPTO %]
 
   <hr>
 
-  [%- INCLUDE jump_block CONTACTS = CONTACTS, SHIPTO = SHIPTO %]
+  [%- INCLUDE jump_block CONTACTS = CONTACTS, SHIPTO = SHIPTO, ADDITIONAL_BILLING_ADDRESSES = ADDITIONAL_BILLING_ADDRESSES %]
 
   <a name="shipping[% loop.count %]"><h1>[% 'Shipping Address' | $T8 %] &quot;[% HTML.escape(row.shiptoname) %]&quot;</h1></a>
 
 
   <hr>
 
-  [%- INCLUDE jump_block CONTACTS = CONTACTS, SHIPTO = SHIPTO %]
+  [%- INCLUDE jump_block CONTACTS = CONTACTS, SHIPTO = SHIPTO, ADDITIONAL_BILLING_ADDRESSES = ADDITIONAL_BILLING_ADDRESSES %]
 
   <a name="contact[% loop.count %]"><h1>[% 'Contact Person' | $T8 %] &quot;[% HTML.escape(row.cp_name) %]&quot;</h1></a>
 
index e867f7a..568324e 100644 (file)
     </p>
    [%- END %]
 [%- END %][%# IF SELF.type == … %]
+  </div>
 
-   <p>
-    [%- L.submit_tag('action_download_sample', LxERP.t8('Download sample file')) %]
-   </p>
-
+  <div>
+    <p>
+      [%- L.submit_tag('action_download_sample', LxERP.t8('Download sample file')) %]
+    </p>
   </div>
 
   <hr>
index f948b5f..6557628 100644 (file)
     <th align="right" nowrap>[% 'E-mail' | $T8 %]</th>
     <td><input name="email" size="35"></td>
    </tr>
+   <tr>
+    <th align="right" nowrap>[% 'All phone numbers' | $T8 %]</th>
+    <td><input name="all_phonenumbers" size="35"></td>
+   </tr>
    <tr>
     <th align="right" nowrap>[% 'Contact person (surname)' | $T8 %]</th>
     <td><input name="cp_name" size="35"></td>
         <label for="l_id">[% 'ID' | $T8 %]</label>
        </td>
        <td>
-        <input name="l_[% db %]number" id="l_[% db %]number" type="checkbox" class="checkbox" value="Y" checked>
-        <label for="l_[% db %]number">[% IF IS_CUSTOMER %][% 'Customer Number' | $T8 %][% ELSE %][% 'Vendor Number' | $T8 %][% END %]</label>
+        <input name="l_[% db | html %]number" id="l_[% db | html %]number" type="checkbox" class="checkbox" value="Y" checked>
+        <label for="l_[% db | html %]number">[% IF IS_CUSTOMER %][% 'Customer Number' | $T8 %][% ELSE %][% 'Vendor Number' | $T8 %][% END %]</label>
        </td>
        <td>
         <input name="l_name" id="l_name" type="checkbox" class="checkbox" value="Y" checked>
         <input name="l_ustid" id="l_ustid" type="checkbox" class="checkbox" value="Y">
         <label for="l_ustid">[% 'VAT ID' | $T8 %]</label>
        </td>
+       <td>
+        <input name="l_main_contact_person" id="l_main_contact_person" type="checkbox" class="checkbox" value="Y">
+        <label for="l_main_contact_person">[% 'Main Contact Person' | $T8 %]</label>
+       </td>
       [% IF !IS_CUSTOMER %]
       </tr>
       [% ELSE %]
         <input name="l_commercial_court" id="l_commercial_court" type="checkbox" class="checkbox" value="Y">
         <label for="l_commercial_court">[% 'Commercial court' | $T8 %]</label>
        </td>
-       <td>
-        <input name="l_main_contact_person" id="l_main_contact_person" type="checkbox" class="checkbox" value="Y">
-        <label for="l_main_contact_person">[% 'Main Contact Person' | $T8 %]</label>
-       </td>
 
-       <td>
       </tr>
       <tr>
        <td>
index a03bcd2..c88711a 100644 (file)
   (4) [% 'The default value depends on the variable type:' | $T8 %]
   <br>
   <ul>
-   <li>[%- 'Text, text field and number variables: The default value will be used as-is.' | $T8 %]</li>
+   <li>[%- 'Text, text field, HTML field and number variables: The default value will be used as-is.' | $T8 %]</li>
    <li>[%- 'Boolean variables: If the default value is non-empty then the checkbox will be checked by default and unchecked otherwise.' | $T8 %]</li>
    <li>[%- 'Date and timestamp variables: If the default value equals \'NOW\' then the current date/current timestamp will be used. Otherwise the default value is copied as-is.' | $T8 %]</li>
   </ul>
   <br>
   <ul>
    <li>[%- 'Text variables: \'MAXLENGTH=n\' sets the maximum entry length to \'n\'.' | $T8 %]</li>
-   <li>[%- 'Text field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the text field. They default to 30 and 5 respectively.' | $T8 %]</li>
+   <li>[%- 'Text field and HTML field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the field in pixels. They default to 225 and 90 respectively.' | $T8 %]</li>
    <li>[%- 'Number variables: \'PRECISION=n\' forces numbers to be shown with exactly n decimal places.' | $T8 %]</li>
    <li>[%- 'Selection fields: The option field must contain the available options for the selection. Options are separated by \'##\', for example \'Early##Normal##Late\'.' | $T8 %]</li>
   </ul>
index 4fdc8a3..2fce8d6 100644 (file)
@@ -20,6 +20,9 @@
   <div class="tabwidget" id="customer_vendor_tabs">
     <ul>
       <li><a href="#billing">[% 'Billing Address' | $T8 %]</a></li>
+      [% IF SELF.is_customer %]
+        <li><a href="#additional_billing_addresses">[% 'Additional Billing Addresses' | $T8 %]</a></li>
+      [% END %]
       <li><a href="#bank">[% 'Bank account' | $T8 %]</a></li>
       <li><a href="#shipto">[% 'Shipping Address' | $T8 %]</a></li>
       <li><a href="#contacts">[% 'Contacts' | $T8 %]</a></li>
@@ -61,6 +64,9 @@
     </ul>
 
     [% PROCESS "customer_vendor/tabs/billing.html" %]
+    [% IF SELF.is_customer %]
+      [% PROCESS "customer_vendor/tabs/additional_billing_addresses.html" %]
+    [% END %]
     [% PROCESS "customer_vendor/tabs/bank.html" %]
     [% PROCESS "customer_vendor/tabs/shipto.html" %]
     [% PROCESS "customer_vendor/tabs/contacts.html" %]
diff --git a/templates/webpages/customer_vendor/tabs/additional_billing_addresses.html b/templates/webpages/customer_vendor/tabs/additional_billing_addresses.html
new file mode 100644 (file)
index 0000000..d8a284c
--- /dev/null
@@ -0,0 +1,127 @@
+[%- USE T8 %]
+[%- USE LxERP %]
+[%- USE L %]
+
+<div id="additional_billing_addresses">
+  <table id="additional_billing_address_table">
+    <tr>
+      <th align="right">[% 'Billing Address' | $T8 %]</th>
+
+      <td>
+        [% L.select_tag(
+             'additional_billing_address.id',
+             SELF.additional_billing_addresses,
+             default     = SELF.additional_billing_address.id,
+             value_key   = 'id',
+             title_key   = 'displayable_id',
+             with_empty  = 1,
+             empty_title = LxERP.t8('New address'),
+             onchange    = "kivi.CustomerVendor.selectAdditionalBillingAddress({onFormSet: function(){ additionalBillingAddressMapWidget.testInputs(); kivi.reinit_widgets(); }});",
+           )
+        %]
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'Default Billing Address' | $T8 %]</th>
+      <td>[% L.yes_no_tag('additional_billing_address.default_address', SELF.additional_billing_address.default_address) %]</td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'Name' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.name', SELF.additional_billing_address.name,  size = 35) %]
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'Department' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.department_1', SELF.additional_billing_address.department_1,  size = 16) %]
+        [% L.input_tag('additional_billing_address.department_2', SELF.additional_billing_address.department_2,  size = 16) %]
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'Street' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.street', SELF.additional_billing_address.street,  size = 35) %]
+
+        <span id="additional_billing_address_map"></span>
+        <script type="text/javascript">
+          additionalBillingAddressMapWidget = new kivi.CustomerVendor.MapWidget('additional_billing_address_');
+          $(function() {
+            additionalBillingAddressMapWidget.render($('#additional_billing_address_map'));
+          });
+        </script>
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'Zipcode' | $T8 %]/[% 'City' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.zipcode', SELF.additional_billing_address.zipcode,  size = 5) %]
+        [% L.input_tag('additional_billing_address.city', SELF.additional_billing_address.city,  size = 30) %]
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'Country' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.country', SELF.additional_billing_address.country,  size = 35) %]
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'GLN' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.gln', SELF.additional_billing_address.gln,  size = 30) %]
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'Contact' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.contact', SELF.additional_billing_address.contact,  size = 30) %]
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'Phone' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.phone', SELF.additional_billing_address.phone,  size = 30) %]
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'Fax' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.fax', SELF.additional_billing_address.fax,  size = 30) %]
+      </td>
+    </tr>
+
+    <tr>
+      <th align="right" nowrap>[% 'E-mail' | $T8 %]</th>
+
+      <td>
+        [% L.input_tag('additional_billing_address.email', SELF.additional_billing_address.email,  size = 45) %]
+      </td>
+    </tr>
+  </table>
+
+  [% L.button_tag('submitInputButton("delete_additional_billing_address");', LxERP.t8('Delete address'), class = 'submit') %]
+  [% IF ( !SELF.additional_billing_address.id ) %]
+    <script type="text/javascript">
+      $('#action_delete_additional_billing_address').hide();
+    </script>
+  [% END %]
+</div>
index c5d4515..300643e 100644 (file)
@@ -9,7 +9,7 @@
 
     <tr height="5"></tr>
 
-    [% IF ( INSTANCE_CONF.get_vertreter ) %]
+    [% IF (0 && INSTANCE_CONF.get_vertreter ) %]
       <tr>
         <th align="right">
           [% IF SELF.is_vendor() %]
index 6e61072..c47d272 100644 (file)
@@ -3,7 +3,7 @@
 [%- USE L %]
 
 <div id="shipto">
-  <table width="100%" id="shipto_table">
+  <table id="shipto_table">
     <tr>
       <th align="right">[% 'Shipping Address' | $T8 %]</th>
 
index d7bd915..2e1fc62 100644 (file)
@@ -1,8 +1,8 @@
 [%- USE T8 %]
 [%- USE L %]
-<h1>[% 'DATEX - Export Assistent' | $T8 %]</h1>
+<h1>[% 'DATEV - Export Assistent' | $T8 %]</h1>
 
-<form method='post' action='[% script %]' id='form'>
+<form method='post' action='[% script | html %]' id='form'>
 
 <table width=100%>
   <tr>
       <table>
         <tr>
           <td align=left nowrap>[% 'Beraternummer' | $T8 %]</td>
-          <td><input name=beraternr size=10 maxlength=7 value="[% beraternr %]"></td>
+          <td>[% L.input_tag("beraternr", beraternr, size=10, maxlength=7) %]</td>
 
           <td align=left nowrap>[% 'DFV-Kennzeichen' | $T8 %]</td>
-          <td><input name=dfvkz size=5 maxlength=2 value="[% dfvkz %]"></td>
+          <td>[% L.input_tag("dfvkz", dfvkz, size=5, maxlength=2) %]</td>
         </tr>
         <tr>
           <td align=left nowrap>[% 'Beratername' | $T8 %]</td>
-          <td><input name=beratername size=10 maxlength=9 value="[% beratername %]"></td>
+          <td>[% L.input_tag("beratername", berater, size=10, maxlength=9) %]</td>
 
           <td align=left nowrap>[% 'Password' | $T8 %]</td>
-          <td><input name=passwort size=5 maxlength=4 value="[% passwort %]"></td>
+          <td>[% L.input_tag("passwort", passwort, size=5, maxlength=4) %]</td>
         </tr>
         <tr>
           <td align=left nowrap>[% 'Mandantennummer' | $T8 %]</td>
-          <td><input name=mandantennr size=10 maxlength=5 value="[% mandantennr %]"></td>
+          <td>[% L.input_tag("mandantennr", mandantennr, size=10, maxlength=5) %]</td>
 
           <td align=left nowrap>[% 'Medium Number' | $T8 %]</td>
-          <td><input name=datentraegernr size=5 maxlength=3 value="[% datentraegernr %]"></td>
+          <td>[% L.input_tag("datentraegernr", datentraegernr, size=5, maxlength=3) %]</td>
         </tr>
         <tr>
           <td></td>
           <td></td>
 
           <td align=left nowrap>[% 'Abrechnungsnummer' | $T8 %]</td>
-          <td><input name=abrechnungsnr size=5 maxlength=3 value="[% abrechnungsnr %]"></td>
+          <td>[% L.input_tag("abrechnungsnr", abrechnungsnr, size=5, maxlength=3) %]</td>
         </tr>
       </table>
     </td>
index 89bc582..80f6c3a 100644 (file)
           [% IF show_pk_option %]
            <td align=left>[% 'Export with CV Charts' | $T8 %]</td>
            <td align=left></td>
-           <td>[% L.checkbox_tag('use_pk', value => 1, checked => 0) %]</td>
+           <td>[% L.checkbox_tag('use_pk', value = 1, checked = 0) %]</td>
           [% ELSE %]
            <td align=left><font color="gray">[% 'Export with CV Charts' | $T8 %]</font></td>
            <td align=left></td>
-           <td>[% L.checkbox_tag('use_pk', value => 1, checked => 0, disabled => 1) %] </td>
+           <td>[% L.checkbox_tag('use_pk', value = 1, checked = 0, disabled = 1) %] </td>
            <td colspan="2"><font color="gray">[% 'Hint: Not all VC Numbers are personal accounts compliant' | $T8 %]</font></td>
           [% END %]
          </tr>
   </tr>
 </table>
 
-<input type=hidden name=beraternr value="[% beraternr %]">
-<input type=hidden name=dfvkz value="[% dfvkz %]">
-<input type=hidden name=beratername value="[% beratername %]">
-<input type=hidden name=passwort value="[% passwort %]">
-<input type=hidden name=mandantennr value="[% mandantennr %]">
-<input type=hidden name=datentraegernr value="[% datentraegernr %]">
-<input type=hidden name=exportformat value="[% exportformat %]">
-<input type=hidden name=abrechnungsnr value="[% abrechnungsnr %]">
+<input type=hidden name=beraternr value="[% beraternr | html %]">
+<input type=hidden name=dfvkz value="[% dfvkz | html %]">
+<input type=hidden name=beratername value="[% beratername | html %]">
+<input type=hidden name=passwort value="[% passwort | html %]">
+<input type=hidden name=mandantennr value="[% mandantennr | html %]">
+<input type=hidden name=datentraegernr value="[% datentraegernr | html %]">
+<input type=hidden name=exportformat value="[% exportformat | html %]">
+<input type=hidden name=abrechnungsnr value="[% abrechnungsnr | html %]">
 
-<input type=hidden name=exporttype value="[% exporttype %]">
+<input type=hidden name=exporttype value="[% exporttype | html %]">
 
 </form>
index 238e58b..f2e19e1 100644 (file)
@@ -21,7 +21,7 @@
 </p>
 
 <p>
- In dem gerade durchgeführten Export gab es [% net_gross_differences.size %]
+ In dem gerade durchgeführten Export gab es [% net_gross_differences.size | html %]
  solcher Fälle. Die Summe aller Abweichungen beläuft sich auf
  [% LxERP.format_amount(sum_net_gross_differences, 2) %].
 </p>
diff --git a/templates/webpages/delivery_order/form.html b/templates/webpages/delivery_order/form.html
new file mode 100644 (file)
index 0000000..d7facc2
--- /dev/null
@@ -0,0 +1,57 @@
+[%- USE T8 %]
+[%- USE LxERP %]
+[%- USE L %]
+[%- USE HTML %]
+<h1>[% FORM.title %] <span id='nr_in_title'>[%- SELF.order.number -%]</span></h1>
+
+<div id="print_options" style="display:none">
+  <form method="post" action="controller.pl" id="print_options_form">
+    [% SELF.print_options %]
+    <br>
+    [% L.button_tag('kivi.DeliveryOrder.print()', LxERP.t8('Print')) %]
+    <a href="#" onclick="$('#print_options').dialog('close');">[% LxERP.t8("Cancel") %]</a>
+  </form>
+</div>
+
+<div id="shipto_dialog" class="hidden"></div>
+
+<form method="post" action="controller.pl" id="order_form">
+  [% L.hidden_tag('callback',             FORM.callback) %]
+  [% L.hidden_tag('type',                 FORM.type) %]
+  [% L.hidden_tag('id',                   SELF.order.id) %]
+  [% L.hidden_tag('converted_from_oe_id', SELF.converted_from_oe_id) %]
+
+  [%- INCLUDE 'common/flash.html' %]
+
+  <div class="tabwidget" id="order_tabs">
+    <ul>
+      <li><a href="#ui-tabs-basic-data">[% 'Basic Data' | $T8 %]</a></li>
+[%- IF INSTANCE_CONF.get_webdav %]
+      <li><a href="#ui-tabs-webdav">[% 'WebDAV' | $T8 %]</a></li>
+[%- END %]
+[%- IF SELF.order.id AND INSTANCE_CONF.get_doc_storage %]
+      <li><a href="controller.pl?action=File/list&file_type=document&object_type=[% HTML.escape(FORM.type) %]&object_id=[% HTML.url(SELF.order.id) %]">[% 'Documents' | $T8 %]</a></li>
+      <li><a href="controller.pl?action=File/list&file_type=attachment&object_type=[% HTML.escape(FORM.type) %]&object_id=[% HTML.url(SELF.order.id) %]">[% 'Attachments' | $T8 %]</a></li>
+[%- END %]
+[%- IF SELF.order.id %]
+      <li><a href="controller.pl?action=RecordLinks/ajax_list&object_model=DeliveryOrder&object_id=[% HTML.url(SELF.order.id) %]">[% 'Linked Records' | $T8 %]</a></li>
+[%- END %]
+    </ul>
+
+    [% PROCESS "delivery_order/tabs/basic_data.html" %]
+    [% PROCESS 'webdav/_list.html' %]
+    <div id="ui-tabs-1">
+      [%- LxERP.t8("Loading...") %]
+    </div>
+
+    <div id="shipto_inputs" class="hidden">
+      [%- PROCESS 'common/_ship_to_dialog.html'
+        vc_obj=SELF.order.customervendor
+        cs_obj=SELF.order.custom_shipto
+        cvars=SELF.order.custom_shipto.cvars_by_config
+        id_selector='#order_shipto_id' %]
+    </div>
+
+  </div>
+
+</form>
diff --git a/templates/webpages/delivery_order/stock_dialog.html b/templates/webpages/delivery_order/stock_dialog.html
new file mode 100644 (file)
index 0000000..f4935cf
--- /dev/null
@@ -0,0 +1,100 @@
+[%- USE T8 %]
+[%- USE HTML %]
+[%- USE LxERP %]
+[%- USE L %]
+ [%- IF delivered %]
+ [%- SET RO = ' readonly' %]
+ [%- END %]
+
+ <table>
+  <tr>
+   <td>[% 'Part Number' | $T8 %]</td>
+   <td>[% part.partnumber | html %]</td>
+  </tr>
+  <tr>
+   <td>[% 'Description' | $T8 %]</td>
+   <td>[% part.description | html %]</td>
+  </tr>
+  <tr>
+   <td>[% 'Qty according to delivery order' | $T8 %]</td>
+   <td>[% LxERP.format_amount(do_qty) %] [% do_unit | html %]</td>
+  </tr>
+ </table>
+
+  [%- UNLESS WHCONTENTS.size %]
+  <p>[% 'There are no items in stock.' | $T8 %]</p>
+  [%- ELSE %]
+
+  [% L.hidden_tag("in_out", in_out) %]
+  [% L.hidden_tag("parts_id", parts_id) %]
+  [% L.hidden_tag("do_qty", do_qty) %]
+  [% L.hidden_tag("do_unit", do_unit) %]
+  [% L.hidden_tag("row", row, class="data-row") %]
+  [% L.hidden_tag("item_id", item_id) %]
+
+  <p>
+   <table id="stock-in-out-table">
+    <tr class="listheading">
+     <th>&nbsp;</th>
+     <th>[% 'Warehouse' | $T8 %]</th>
+     <th>[% 'Bin' | $T8 %]</th>
+     <th>[% 'Charge Number' | $T8 %]</th>
+     [% IF INSTANCE_CONF.get_show_bestbefore %]
+     <th>[% 'Best Before' | $T8 %]</th>
+     [% END %]
+     [%- UNLESS delivered %]
+     <th align="right">[% 'Available qty' | $T8 %]</th>
+     [%- END %]
+     <th align="right">[% 'Qty' | $T8 %]</th>
+     <th align="right">[% 'Unit' | $T8 %]</th>
+    </tr>
+
+    [%- FOREACH row = WHCONTENTS %]
+    <tr [% IF row.stock_error %] class="error"[% ELSE %]class="listrow"[% END %]>
+     <td>[% loop.count %]</td>
+     <td>[% row.warehousedescription | html %]</td>
+     <td>[% row.bindescription | html %]</td>
+     <td>[% row.chargenumber | html %]</td>
+     [% IF INSTANCE_CONF.get_show_bestbefore %]
+     <td>[% row.bestbefore | html %]</td>
+     [% END %]
+
+     [%- IF delivered %]
+
+     <td>[% LxERP.format_amount(row.stock_qty) | html %]</td>
+     <td>
+      [% row.stock_unit | html %]
+      [% L.hidden_tag("unit", row.stock_unit, class="data-unit") %]
+     </td>
+
+     [%- ELSE %]
+
+     <td>[% row.available_qty | html %]</td>
+     <td>
+      [% L.input_tag("qty", row.stock_qty                              ? LxERP.format_amount(row.stock_qty)
+                          : (WHCONTENTS.size == 1) && (!row.stock_qty) ? LxERP.format_amount(do_qty)
+                          : "", class="numeric data-qty", size="12") %]</td>
+     <td>[% L.select_tag("unit_" _ loop.count, part.unit_obj.convertible_units, value_key="name", default=row.stock_unit, class="data-unit") %]</td>
+
+     [%- END %]
+     <td style="display:none">
+      [% L.hidden_tag("warehouse_id", row.warehouse_id, class="data-warehouse-id") %]
+      [% L.hidden_tag("bin_id", row.bin_id, class="data-bin-id") %]
+      [% L.hidden_tag("chargenumber", row.chargenumber, class="data-chargenumber") %]
+      [% L.hidden_tag("delivery_order_items_stock_id", row.delivery_order_items_stock_id, class="data-stock-id") %]
+      [% L.hidden_tag("bestbefore", row.bestbefore, class="data-bestbefore") IF INSTANCE_CONF.get_show_bestbefore %]
+     </td>
+    </tr>
+
+    [%- END %]
+   </table>
+  </p>
+
+  <hr size="3" noshade>
+
+  <p>[% L.button_tag('kivi.DeliveryOrder.save_updated_stock()', LxERP.t8('Save')) IF !delivered %]</p>
+
+  [%- END %]
+ </form>
+
+
diff --git a/templates/webpages/delivery_order/tabs/_business_info_row.html b/templates/webpages/delivery_order/tabs/_business_info_row.html
new file mode 100644 (file)
index 0000000..cdd61a6
--- /dev/null
@@ -0,0 +1,10 @@
+[%- USE T8 %][%- USE HTML %]
+
+<tr id='business_info_row' [%- IF !SELF.order.customervendor.business_id %]style='display:none'[%- END %]>
+  <th align="right">[%- IF SELF.cv == 'customer' -%]
+                      [%- 'Customer type' | $T8 -%]
+                    [%- ELSE -%]
+                      [%- 'Vendor type' | $T8 -%]
+                    [%- END -%]</th>
+  <td>[% HTML.escape(SELF.order.customervendor.business.description) %]; [% 'Trade Discount' | $T8 %] [% SELF.order.customervendor.business.discount_as_percent %] %</td>
+</tr>
diff --git a/templates/webpages/delivery_order/tabs/_item_input.html b/templates/webpages/delivery_order/tabs/_item_input.html
new file mode 100644 (file)
index 0000000..ab62bd9
--- /dev/null
@@ -0,0 +1,44 @@
+[%- USE T8 %][%- USE HTML %][%- USE LxERP %][%- USE L %][%- USE P %]
+
+ <div>
+  <table id="input_row_table_id">
+    <thead>
+      <tr class="listheading">
+        <th class="listheading" nowrap >[%- '+'            | $T8 %] </th>
+        <th class="listheading" nowrap >[%- 'position'     | $T8 %] </th>
+        <th class="listheading" nowrap >[%- 'Part'         | $T8 %] </th>
+        <th class="listheading" nowrap >[%- 'Description'  | $T8 %] </th>
+        <th class="listheading" nowrap width="5" >[%- 'Qty'          | $T8 %] </th>
+        <th></th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr valign="top" class="listrow">
+        <td class="tooltipster-html" title="[%- 'Create a new part' | $T8 -%]">
+          [% SET type_options = [[ 'part', LxERP.t8('Part') ], [ 'assembly', LxERP.t8('Assembly') ]] %]
+          [%- IF INSTANCE_CONF.get_feature_experimental_assortment %]
+            [%- type_options.push([ 'assortment', LxERP.t8('Assortment')]) %]
+          [%- END %]
+          [% L.select_tag('add_item.create_part_type', type_options) %]
+          [% L.button_tag('kivi.DeliveryOrder.create_part()', LxERP.t8('+')) %]
+        </td>
+        <td>[% L.input_tag('add_item.position', '', size = 5, class="add_item_input numeric") %]</td>
+        <td>
+          [%- SET PARAM_KEY = SELF.type_data.properties('is_customer') ? 'with_customer_partnumber' : 'with_makemodel' -%]
+          [%- SET PARAM_VAL = SELF.search_cvpartnumber -%]
+          [% P.part.picker('add_item.parts_id', SELF.created_part, style='width: 300px', class="add_item_input",
+                            fat_set_item=1,
+                            multiple_pos_input=1,
+                            action={set_multi_items='kivi.DeliveryOrder.add_multi_items'},
+                            classification_id=SELF.part_picker_classification_ids.as_list.join(','),
+                            $PARAM_KEY=PARAM_VAL) %]</td>
+        <td>[% L.input_tag('add_item.description', SELF.created_part.description, class="add_item_input") %]</td>
+        <td>
+          [% L.input_tag('add_item.qty_as_number', '', size = 5, class="add_item_input numeric") %]
+          [% L.hidden_tag('add_item.unit', SELF.created_part.unit, class="add_item_input") %]
+        </td>
+        <td>[% L.button_tag('kivi.DeliveryOrder.add_item()', LxERP.t8('Add part')) %]</td>
+      </tr>
+    </tbody>
+  </table>
+ </div>
diff --git a/templates/webpages/delivery_order/tabs/_row.html b/templates/webpages/delivery_order/tabs/_row.html
new file mode 100644 (file)
index 0000000..82422ef
--- /dev/null
@@ -0,0 +1,110 @@
+[%- USE T8 %]
+[%- USE HTML %]
+[%- USE LxERP %]
+[%- USE L %]
+[%- USE P %]
+
+<tbody class="row_entry listrow" data-position="[%- HTML.escape(ITEM.position) -%]"[%- IF MYCONFIG.show_form_details -%] data-expanded="1"[%- END -%]>
+  <tr>
+    <td align="center">
+      [%- IF MYCONFIG.show_form_details %]
+        [% L.img_tag(src="image/collapse.svg",
+                     alt=LxERP.t8('Hide details'), title=LxERP.t8('Hide details'), class="expand") %]
+      [%- ELSE %]
+        [% L.img_tag(src="image/expand.svg",
+                     alt=LxERP.t8('Show details'), title=LxERP.t8('Show details'), class="expand") %]
+      [%- END %]
+      [% L.hidden_tag("orderitem_ids[+]", ID) %]
+      [% L.hidden_tag("converted_from_orderitems_ids[+]", ITEM.converted_from_orderitems_id) %]
+      [% L.hidden_tag("order.orderitems[+].id", ITEM.id, id='item_' _ ID) %]
+      [% L.hidden_tag("order.orderitems[].stock_info", ITEM.stock_info, class="data-stock-info") %]
+      [% L.hidden_tag("order.orderitems[].parts_id", ITEM.parts_id) %]
+    </td>
+    <td>
+      <div name="position" class="numeric">
+        [% HTML.escape(ITEM.position) %]
+      </div>
+    </td>
+    <td align="center">
+      <img src="image/updown.png" alt="[%- LxERP.t8('reorder item') %]" class="dragdrop">
+    </td>
+    <td align="center">
+      [%- L.button_tag("kivi.DeliveryOrder.delete_order_item_row(this)",
+                       LxERP.t8("X"),
+                       confirm=LxERP.t8("Are you sure?")) %]
+    </td>
+    [%- IF SELF.show_update_button -%]
+    <td align="center">
+      [%- L.img_tag(src="image/rotate_cw.svg",
+                    alt=LxERP.t8('Update from master data'),
+                    title= LxERP.t8('Update from master data'),
+                    onclick="if (!confirm('" _ LxERP.t8("Are you sure to update this position from master data?") _ "')) return false; kivi.DeliveryOrder.update_row_from_master_data(this);",
+                    id='update_from_master') %]
+    </td>
+    [%- END -%]
+    <td>
+      <div name="partnumber">
+        [%- P.link_tag(SELF.url_for(controller='Part', action='edit', 'part.id'=ITEM.part.id), ITEM.part.partnumber, target="_blank", title=LxERP.t8('Open in new window')) -%]
+      </div>
+    </td>
+    [%- IF SELF.search_cvpartnumber -%]
+    <td>
+      <div name="cvpartnumber">[% HTML.escape(ITEM.cvpartnumber) %]</div>
+    </td>
+    [%- END -%]
+    <td>
+      <div name="partclassification">[% ITEM.part.presenter.typeclass_abbreviation %]</div>
+    </td>
+    <td>
+      [% L.areainput_tag("order.orderitems[].description",
+                     ITEM.description,
+                     size='40',
+                     style='width: 300px') %]
+      [%- L.hidden_tag("order.orderitems[].longdescription", ITEM.longdescription) %]
+      [%- L.button_tag("kivi.DeliveryOrder.show_longdescription_dialog(this)", LxERP.t8("L")) %]
+    </td>
+    [%- IF (SELF.type == "sales_order" || SELF.type == "purchase_order") -%]
+    <td nowrap>
+      [%- L.div_tag(LxERP.format_amount(ITEM.shipped_qty, 2, 0) _ ' ' _ ITEM.unit, name="shipped_qty", class="numeric") %]
+    </td>
+    [%- END -%]
+    <td nowrap>
+      [%- L.input_tag("order.orderitems[].qty_as_number",
+                      ITEM.qty_as_number,
+                      size = 5,
+                      class="reformat_number numeric") %]
+      [%- IF ITEM.part.formel -%]
+        [%- L.button_tag("kivi.DeliveryOrder.show_calculate_qty_dialog(this)", LxERP.t8("*/")) %]
+        [%- L.hidden_tag("formula[+]", ITEM.part.formel) -%]
+      [%- END -%]
+    </td>
+    <td nowrap>
+      [%- L.select_tag("order.orderitems[].unit",
+                      ITEM.part.available_units,
+                      default = ITEM.unit,
+                      title_key = 'name',
+                      value_key = 'name',
+                      class = 'unitselect') %]
+    </td>
+
+    <td>
+      <span id="stock_[% ID %]" class="data-stock-qty">[% SELF.calculate_stock_in_out(ITEM) %] [% ITEM.unit %]</span>
+      [% P.button_tag("kivi.DeliveryOrder.open_stock_in_out_dialog(this, '" _ in_out _"')", "?") %]
+    </td>
+  </tr>
+
+  <tr [%- IF !MYCONFIG.show_form_details -%]style="display:none"[%- END -%]>
+    <td colspan="100%">
+      [%- IF MYCONFIG.show_form_details || ITEM.render_second_row %]
+        <div name="second_row" data-loaded="1">
+          [%- PROCESS delivery_order/tabs/_second_row.html ITEM=ITEM TYPE=SELF.type %]
+        </div>
+      [%- ELSE %]
+        <div name="second_row" id="second_row_[% ID %]">
+          [%- LxERP.t8("Loading...") %]
+        </div>
+      [%- END %]
+    </td>
+  </tr>
+
+</tbody>
diff --git a/templates/webpages/delivery_order/tabs/_second_row.html b/templates/webpages/delivery_order/tabs/_second_row.html
new file mode 100644 (file)
index 0000000..6b140ac
--- /dev/null
@@ -0,0 +1,45 @@
+[%- USE T8 %]
+[%- USE HTML %]
+[%- USE LxERP %]
+[%- USE L %]
+[%- USE P %]
+
+<table>
+  <tr><td colspan="100%">
+    [%- IF (TYPE == "sales_order" || TYPE == "purchase_order") %]
+      <b>[%- 'Serial No.' | $T8 %]</b>&nbsp;
+      [%- L.input_tag("order.orderitems[].serialnumber", ITEM.serialnumber, size = 15) %]&nbsp;
+    [%- END %]
+    <b>[%- 'Project' | $T8 %]</b>&nbsp;
+    [% P.project.picker("order.orderitems[].project_id", ITEM.project_id, size = 15) %]&nbsp;
+    [%- IF (TYPE == "sales_order" || TYPE == "purchase_order") %]
+      <b>[%- 'Reqdate' | $T8 %]</b>&nbsp;
+      [% L.date_tag("order.orderitems[].reqdate_as_date", ITEM.reqdate_as_date) %]&nbsp;
+    [%- END %]
+    <b>[%- 'On Hand' | $T8 %]</b>&nbsp;
+      <span[%- IF ITEM.part.onhand < ITEM.part.rop -%] class="numeric plus0"[%- END -%]>
+        [%- ITEM.part.onhand_as_number -%]&nbsp;[%- ITEM.part.unit -%]
+      </span>&nbsp;
+  </td></tr>
+
+  <tr>
+    [%- SET n = 0 %]
+    [%- FOREACH var = ITEM.cvars_by_config %]
+    [%- NEXT UNLESS (var.config.processed_flags.editable && ITEM.part.cvar_by_name(var.config.name).is_valid) %]
+    [%- SET n = n + 1 %]
+    <th>
+      [% var.config.description %]
+    </th>
+    <td>
+      [% L.hidden_tag('order.orderitems[].custom_variables[+].config_id', var.config.id) %]
+      [% L.hidden_tag('order.orderitems[].custom_variables[].id', var.id) %]
+      [% L.hidden_tag('order.orderitems[].custom_variables[].sub_module', var.sub_module) %]
+      [% INCLUDE 'common/render_cvar_input.html' var_name='order.orderitems[].custom_variables[].unparsed_value' %]
+    </td>
+    [%- IF (n % (MYCONFIG.form_cvars_nr_cols || 3)) == 0 %]
+
+  </tr><tr>
+    [%- END %]
+    [%- END %]
+  </tr>
+</table>
diff --git a/templates/webpages/delivery_order/tabs/basic_data.html b/templates/webpages/delivery_order/tabs/basic_data.html
new file mode 100644 (file)
index 0000000..f4c052b
--- /dev/null
@@ -0,0 +1,280 @@
+[%- USE T8 %]
+[%- USE HTML %]
+[%- USE LxERP %]
+[%- USE L %]
+[%- USE P %]
+
+[%- INCLUDE 'generic/set_longdescription.html' %]
+
+<div id="ui-tabs-basic-data">
+  <table width="100%">
+    <tr valign="top">
+      <td>
+        <table width="100%">
+          <tr>
+            <th align="right">[%- SELF.cv == "customer" ? LxERP.t8('Customer') : LxERP.t8('Vendor') -%]</th>
+            [% SET cv_id = SELF.cv _ '_id' %]
+            <td>
+              [% P.customer_vendor.picker("order.${SELF.cv}" _ '_id', SELF.order.$cv_id, type=SELF.cv, style='width: 300px') %]
+              [% P.button_tag("kivi.DeliveryOrder.show_vc_details_dialog()", LxERP.t8("Details (one letter abbreviation)")) %]
+            </td>
+          </tr>
+
+          <tr id='cp_row' [%- IF !SELF.order.${SELF.cv}.contacts.size %]style='display:none'[%- END %]>
+            <th align="right">[% 'Contact Person' | $T8 %]</th>
+            <td>[% L.select_tag('order.cp_id',
+                                SELF.order.${SELF.cv}.contacts,
+                                default=SELF.order.cp_id,
+                                title_key='full_name_dep',
+                                value_key='cp_id',
+                                with_empty=1,
+                                style='width: 300px') %]</td>
+          </tr>
+
+          <tr>
+            <th align="right">[% 'Shipping Address' | $T8 %]</th>
+            <td>
+              <span id='shipto_selection' [%- IF !SELF.order.${SELF.cv}.shipto.size %]style='display:none'[%- END %]>
+                [% shiptos = [ { shipto_id => "", displayable_id => LxERP.t8("No/individual shipping address") } ] ;
+                   FOREACH s = SELF.order.${SELF.cv}.shipto ;
+                     shiptos.push(s) ;
+                   END ;
+                   L.select_tag('order.shipto_id',
+                                 shiptos,
+                                 default=SELF.order.shipto_id,
+                                 title_key='displayable_id',
+                                 value_key='shipto_id',
+                                 with_empty=0,
+                                 style='width: 300px') %]
+              </span>
+              [% L.button_tag("kivi.DeliveryOrder.edit_custom_shipto()", LxERP.t8("Custom shipto")) %]
+            </td>
+          </tr>
+
+          [%- PROCESS delivery_order/tabs/_business_info_row.html SELF=SELF %]
+
+[%- IF SELF.all_languages.size %]
+          <tr>
+            <th align="right">[% 'Language' | $T8 %]</th>
+            <td>
+              [% L.select_tag('order.language_id', SELF.all_languages, default=SELF.order.language_id, title_key='description', with_empty=1, style='width:300px') %]
+            </td>
+          </tr>
+[%- END %]
+
+[%- IF SELF.all_departments.size %]
+          <tr>
+            <th align="right">[% 'Department' | $T8 %]</th>
+            <td>
+              [% L.select_tag('order.department_id', SELF.all_departments, default=SELF.order.department_id, title_key='description', with_empty=1, style='width:300px') %]
+            </td>
+          </tr>
+[%- END %]
+
+          <tr>
+            <th align="right">[% 'Shipping Point' | $T8 %]</th>
+            <td>[% L.input_tag('order.shippingpoint', SELF.order.shippingpoint, style='width: 300px') %]</td>
+          </tr>
+
+          <tr>
+            <th align="right">[% 'Ship via' | $T8 %]</th>
+            <td>[% L.input_tag('order.shipvia', SELF.order.shipvia, style='width: 300px') %]</td>
+          </tr>
+
+          <tr>
+            <th align="right">[% 'Transaction description' | $T8 %]</th>
+            <td>[% L.input_tag('order.transaction_description', SELF.order.transaction_description, 'data-validate'=INSTANCE_CONF.get_require_transaction_description_ps ? 'required' : '', style='width: 300px') %]</td>
+          </tr>
+
+          <tr>
+            <th align="right">[% 'Project Number' | $T8 %]</th>
+            <td>[% P.project.picker('order.globalproject_id', SELF.order.globalproject_id, style='width: 300px') %]</td>
+          </tr>
+
+        </table>
+      </td>
+
+      <td align="right">
+        <table>
+
+          <tr>
+            <td colspan="2" align="center" id="data-status-line">[% SELF.order.presenter.status_line %]</td>
+          </tr>
+
+          <tr>
+            <th align="right">[% 'Employee' | $T8 %]</th>
+            <td>[% L.select_tag('order.employee_id',
+              SELF.all_employees,
+              default=(SELF.order.employee_id ? SELF.order.employee_id : SELF.current_employee_id),
+              title_key='safe_name') %]</td>
+          </tr>
+
+          [% IF SELF.cv == 'customer' %]
+          <tr>
+            <th align="right">[% 'Salesman' | $T8 %]</th>
+            <td>[% L.select_tag('order.salesman_id',
+              SELF.all_salesmen,
+              default=(SELF.order.salesman_id ? SELF.order.salesman_id : SELF.current_employee_id),
+              title_key='safe_name') %]</td>
+          </tr>
+          [% END %]
+
+          <tr>
+            <th width="70%" align="right" nowrap>[% 'Delivery Order Number' | $T8 %]</th>
+            <td>[% L.input_tag('order.donumber', SELF.order.donumber, size = 11, onchange='kivi.DeliveryOrder.set_number_in_title(this)') %]</td>
+          </tr>
+
+          <tr>
+            <th width="70%" align="right" nowrap>[% 'Order Number' | $T8 %]</th>
+            <td>[% L.input_tag('order.ordnumber', SELF.order.ordnumber, size = 11) %]</td>
+          </tr>
+
+          <tr>
+            <th width="70%" align="right" nowrap>[% IF SELF.type_data.properties('is_customer') %][% 'Customer Order Number' | $T8 %][% ELSE %][% 'Vendor Order Number' | $T8 %][% END %]</th>
+            <td>[% L.input_tag('order.cusordnumber', SELF.order.cusordnumber, size = 11) %]</td>
+          </tr>
+
+          <tr>
+            <th width="70%" align="right" nowrap>[% 'Delivery Order Date' | $T8 %]</th>
+            <td>[% L.date_tag('order.transdate_as_date', SELF.order.transdate_as_date) %]</td>
+          </tr>
+
+          <tr>
+            <th width="70%" align="right" nowrap>[% 'Reqdate' | $T8 %]</th>
+            <td>[% L.date_tag('order.reqdate_as_date', SELF.order.reqdate_as_date, class=reqdate_class) %]</td>
+          </tr>
+
+          <tr>
+            <th width="70%" align="right" nowrap>[% 'Insert Date' | $T8 %]</th>
+            <td>[% SELF.order.itime_as_date %]</td>
+          </tr>
+        </table>
+
+      </td>
+    </tr>
+  </table>
+
+  [%- PROCESS delivery_order/tabs/_item_input.html SELF=SELF %]
+
+  [% L.button_tag('kivi.DeliveryOrder.open_multi_items_dialog()', LxERP.t8('Add multiple items')) %]
+
+  <table width="100%">
+    <tr>
+      <td>
+        [%- IF SELF.positions_scrollbar_height -%]
+          [%- SET scroll_style = 'style="overflow-y: auto; height:' _ SELF.positions_scrollbar_height _ 'vh;"' -%]
+        [%- ELSE -%]
+          [%- SET scroll_style = '' -%]
+        [%- END -%]
+        <div id="row_table_scroll_id" [%- scroll_style -%]>
+          <table id="row_table_id" width="100%">
+            <thead>
+              <tr class="listheading">
+                <th class="listheading" style='text-align:center' nowrap width="1">
+                  [%- IF MYCONFIG.show_form_details %]
+                    [%- L.img_tag(src="image/collapse.svg", alt=LxERP.t8('Hide all details'), title=LxERP.t8('Hide all details'), id='expand_all', "data-expanded"="1") %]
+                  [%- ELSE %]
+                    [%- L.img_tag(src="image/expand.svg", alt=LxERP.t8('Show all details'), title=LxERP.t8('Show all details'), id='expand_all') %]
+                  [%- END %]
+                </th>
+                <th class="listheading" nowrap width="3" >[%- 'position'     | $T8 %] </th>
+                <th class="listheading" style='text-align:center' nowrap width="1"><img src="image/updown.png" alt="[%- LxERP.t8('reorder item') %]"></th>
+                <th class="listheading" style='text-align:center' nowrap width="1"><img src="image/close.png" alt="[%- LxERP.t8('delete item') %]"></th>
+                [%- IF SELF.show_update_button -%]
+                <th class="listheading" style='text-align:center' nowrap width="1">
+                  [%- L.img_tag(src="image/rotate_cw.svg",
+                                alt=LxERP.t8('Update from master data'),
+                                title= LxERP.t8('Update from master data'),
+                                onclick="if (!confirm('" _ LxERP.t8("Are you sure to update all positions from master data?") _ "')) return false; kivi.DeliveryOrder.update_all_rows_from_master_data();",
+                                id='update_from_master') %]
+                </th>
+                [%- END %]
+                <th id="partnumber_header_id"   class="listheading" nowrap width="15"><a href='#' onClick='javascript:kivi.DeliveryOrder.reorder_items("partnumber")'> [%- 'Partnumber'  | $T8 %]</a></th>
+                [%- IF SELF.search_cvpartnumber -%]
+                <th id="cvpartnumber_header_id" class="listheading" nowrap width="15"><a href='#' onClick='javascript:kivi.DeliveryOrder.reorder_items("cvpartnumber")' > [%- SELF.cv == "customer" ? LxERP.t8('Customer Part Number') : LxERP.t8('Model') %]</a></th>
+                [%- END -%]
+                <th id="partclass_header_id"    class="listheading" nowrap width="2">[%- 'Type'  | $T8 %]</th>
+                <th id="description_header_id"  class="listheading" nowrap           ><a href='#' onClick='javascript:kivi.DeliveryOrder.reorder_items("description")'>[%- 'Description' | $T8 %]</a></th>
+                [%- IF (SELF.type == "sales_order" || SELF.type == "purchase_order") -%]
+                <th id="shipped_qty_header_id"  class="listheading" nowrap width="5" ><a href='#' onClick='javascript:kivi.DeliveryOrder.reorder_items("shipped_qty")'>[%- 'Delivered'   | $T8 %]</a></th>
+                [%- END -%]
+                <th id="qty_header_id"          class="listheading" nowrap width="5" ><a href='#' onClick='javascript:kivi.DeliveryOrder.reorder_items("qty")'>        [%- 'Qty'         | $T8 %]</a></th>
+                <th class="listheading" nowrap width="5" >[%- 'Unit'         | $T8 %] </th>
+                [% IF in_out == 'in' %]
+                <th class="listheading" nowrap width="5" >[%- 'Transfer To Stock' | $T8 %] </th>
+                [% END %]
+                [% IF in_out == 'out' %]
+                <th class="listheading" nowrap width="5" >[%- 'Release From Stock' | $T8 %] </th>
+                [% END %]
+              </tr>
+            </thead>
+
+            [%- FOREACH item = SELF.order.items_sorted %]
+              [%- PROCESS delivery_order/tabs/_row.html ITEM=item ID=(item.id||item.new_fake_id)  -%]
+            [%- END %]
+
+          </table>
+        </div>
+
+      </td>
+    </tr>
+
+    <tr>
+    </tr>
+
+    <tr>
+      <td colspan="100%" width="100%">
+        <table width="100%">
+          <tr>
+            <td>
+              <table>
+                <tr>
+                  <th align="left">[% 'Notes' | $T8 %]</th>
+                  <th align="left">[% 'Internal Notes' | $T8 %]</th>
+                </tr>
+                <tr valign="top">
+                  <td>
+                    [% L.textarea_tag('order.notes', SELF.order.notes, wrap="soft", style="width: 350px; height: 150px", class="texteditor") %]
+                  </td>
+                  <td>
+                    [% L.textarea_tag('order.intnotes', SELF.order.intnotes, wrap="soft", style="width: 350px; height: 150px") %]
+                  </td>
+                </tr>
+              </table>
+            </td>
+
+            <td>
+              <table>
+                <tr>
+                  <th align="right">[% 'Payment Terms' | $T8 %]</th>
+                  <td>[% L.select_tag('order.payment_id',
+                                      SELF.all_payment_terms,
+                                      default = SELF.order.payment_id,
+                                      with_empty = 1,
+                                      title_key = 'description',
+                                      style = 'width: 250px') %]</td>
+                </tr>
+                <tr>
+                  <th align="right">[% 'Delivery Terms' | $T8 %]</th>
+                  <td>[% L.select_tag('order.delivery_term_id',
+                                      SELF.all_delivery_terms,
+                                      default = SELF.order.delivery_term_id,
+                                      with_empty = 1,
+                                      title_key = 'description',
+                                      style = 'width: 250px') %]</td>
+                </tr>
+              </table>
+            </td>
+
+          </tr>
+        </table>
+      </td>
+    </tr>
+
+  </table>
+
+  [% L.hidden_tag('order.taxzone_id', SELF.order.taxzone_id) %]
+
+</div>
+
+[% L.sortable_element('#row_table_id') %]
index d16a9f2..c94135f 100644 (file)
                      style      => 'width: 200px') %]
    </td>
   </tr>
+  [%- IF SELF.all_partsgroups.size %]
+  <tr>
+     <th align="right">[% 'Partsgroup' | $T8 %]</th>
+     <td>[%- L.select_tag('filter.part.partsgroup_id', SELF.all_partsgroups, default=filter.part.partsgroup_id, title_key='partsgroup', value_key='id', with_empty=1 style='width: 200px') %]</td>
+  </tr>
+  [% END %]
   <tr>
    <th align="right">[% 'Type' | $T8 %]</th>
    <td>
index 9ff8e98..bee0ee6 100644 (file)
          </td>
         </tr>
 
+        [%- IF (vc == 'customer') && VC_OBJ.additional_billing_addresses.as_list.size %]
+        <tr>
+          <th align="right">[% 'Custom Billing Address' | $T8 %]</th>
+          <td>
+            [% L.select_tag('billing_address_id', VC_OBJ.additional_billing_addresses,
+                            with_empty=1, default=billing_address_id, value_key='id', title_key='displayable_id', style='width: 250px') %]
+          </td>
+        </tr>
+        [%- END %]
+
         [%- IF business %]
         <tr>
          <th align="right">[% IF is_customer %][% 'Customer type' | $T8 %][% ELSE %][% 'Vendor type' | $T8 %][% END %]</th>
 
        <tr>
         <th width="70%" align="right" nowrap>[% 'Delivery Order Number' | $T8 %]</th>
-        <td><input name="donumber" id="donumber" size="11" value="[% HTML.escape(donumber) %]"[% RO %]></td>
+        <td>
+[%- IF !is_customer || INSTANCE_CONF.get_sales_purchase_record_numbers_changeable %]
+          [% L.input_tag("donumber", donumber, size="11", readonly=delivered) %]
+[%- ELSIF id %]
+          [% HTML.escape(donumber) %]
+          [% L.hidden_tag("donumber", donumber) %]
+[%- ELSE %]
+          [% LxERP.t8("will be set upon saving") %]
+[%- END %]
+        </td>
        </tr>
 
        <tr>
index 1a40a45..b740f58 100644 (file)
@@ -1,13 +1,14 @@
 [%- USE T8 %]
-[%- USE HTML %]
+[%- USE HTML %][%- USE L -%]
 <h1>[% title %]</h1>
 
  <script type="text/javascript">
   <!--
       function email_updated() {
         window.opener.document.getElementsByName(document.Form.input_subject.value)[0].value = document.getElementsByName("email_subject")[0].value;
-        window.opener.document.getElementsByName(document.Form.input_body.value)[0].value = document.getElementsByName("email_body")[0].value;
-        window.opener.document.getElementsByName(document.Form.input_attachment.value)[0].value = document.getElementsByName("email_attachment")[0].value;        self.close();
+        window.opener.document.getElementsByName(document.Form.input_body.value)[0].value = $("#email_body").val();
+        window.opener.document.getElementsByName(document.Form.input_attachment.value)[0].value = document.getElementsByName("email_attachment")[0].value;
+        self.close();
       }
     -->
  </script>
@@ -26,7 +27,7 @@
 
    <tr>
     <td valign="top">[% 'Body:' | $T8 %]</td>
-    <td valign="top"><textarea id="email_body" name="email_body" rows="20" cols="70" wrap="soft">[% HTML.escape(email_body) %]</textarea></td>
+    <td valign="top">[% L.textarea_tag('email_body', email_body, rows=20, cols=70, class='texteditor') %]</td>
    </tr>
 
    <tr>
index bfa979d..949d060 100644 (file)
@@ -20,6 +20,7 @@
   <table width="100%" id="dunning_invoice_list">
    <th class="listheading" colspan="2">[% 'Current / Next Level' | $T8 %]</th>
 
+   <th class="listheading">[% 'Payment description' | $T8 %]</th>
    <th class="listheading">
     [% L.checkbox_tag('selectall_active', checkall='INPUT[name*=active_]', checked=all_active) %]
     <label for="selectall_active">[% 'Active?' | $T8 %]</label>
        [% FOREACH cfg_row = row.DUNNING_CONFIG %]<option value="[% HTML.escape(cfg_row.id) %]" [% IF cfg_row.SELECTED %]selected[% END %]>[% HTML.escape(cfg_row.dunning_description) %]</option>[% END %]
       </select>
      </td>
+     <td>[% HTML.escape(row.payment_term) %]</td>
 
      <td><input type="checkbox" name="active_[% loop.count %]" value="1" [% IF row.active %]checked[% END %]></td>
-     <td><input type="checkbox" name="email_[% loop.count %]" value="1" [% IF row.email %]checked[% END %]></td>
+     <td><input type="checkbox" name="email_[% loop.count %]" value="1" [% IF row.email && row.cv_email %]checked[% END %]>[% HTML.escape(row.cv_email) %]</td>
      <td><input type="checkbox" name="include_invoice_[% loop.count %]" value="1" [% IF row.print_original_invoice %]checked[% END %]></td>
      <td><input type="hidden" name="customername_[% loop.count %]" size="6" value="[% HTML.escape(row.customername) %]">[% HTML.escape(row.customername) %]</td>
      <td><input type="hidden" name="department_[% loop.count %]" size="6" value="[% HTML.escape(row.departmentname) %]">[% HTML.escape(row.departmentname) %]</td>
index 20444a9..b484bc7 100644 (file)
@@ -1,4 +1,4 @@
-[% USE HTML %][% USE L %][% USE LxERP %]
+[% USE HTML %][% USE L %][% USE LxERP %][%- USE P -%]
 
  <h1>[% FORM.title %]</h1>
 
 
    <tr class="listrow">
     <th>[%- LxERP.t8("Body") %]</th>
-    <td><pre>[% HTML.escape(SELF.entry.body) %]</pre></td>
+    <td>
+     [%- IF SELF.entry.headers.match('(?i)content-type:.*text/html') %]
+      [% P.restricted_html(SELF.entry.body) %]
+     [%- ELSE %]
+      <pre>[% HTML.escape(SELF.entry.body) %]</pre>
+     [%- END %]
+    </td>
    </tr>
  </table>
 
index 315e886..2868d4f 100644 (file)
@@ -12,7 +12,7 @@
  [%- FOREACH source = SOURCES %]
   <table style="width: 100%" >
    <thead>
-    <tr><th class="listheading" colspan="6">[% source.title %]</th></tr>
+    <tr><th class="listheading" colspan="[% IF file_type == 'image' %]8[% ELSE %]6[% END %]">[% source.title %]</th></tr>
     <tr>
      [%- SET checkname = source.chk_action %]
      [%- IF is_global %]
@@ -29,6 +29,7 @@
       <th class="listheading" width="3%">[% L.checkbox_tag(checkname _ '_checkall') %]</th>
       <th class="listheading" width="7%">[% source.chkall_title %]</th>
      [%- END %]
+     <th class="listheading" width="2%"><b>[%  LxERP.t8('Version') %]</b></th>
      <th class="listheading" width="15%"><b>[%  LxERP.t8('Date') %]</b></th>
      <th class="listheading" width="20%"><b>[%  source.file_title %]</b></th>
      [%- IF file_type == 'image' %]
 
    <tbody>
     [%- FOREACH file = source.files %]
-     <tr class="listrow[% loop.count % 2 %]">
+     [%- is_other_version = 1 IF last_id == file.id %]
+     [%- last_id = file.id %]
+     [%- IF !is_other_version %]
+      [%- row_cnt = row_cnt + 1 %]
+      <tr class="listrow[% row_cnt % 2 %]">
+     [%- ELSE %]
+      <tr class="[% 'version_row_' _ file.id %] listrow[% row_cnt % 2 %] hidden">
+     [%- END %]
       [%- IF edit_attachments %]
        <td>[%- L.checkbox_tag(checkname _ '[]', 'value'=file.id _ '_' _ file.version, 'class'=checkname) %]</td>
        <td></td>
       [%- END %]
-      <td>[% file.mtime_as_timestamp_s %][% L.hidden_tag("version[]", file.version) %]</td>
+      <td align="right" [%- IF file.version_count > 1 && !is_other_version %] class="cursor-pointer" onclick="kivi.File.toggle_versions('[% file.id %]')"[%- END %]>
+       [%- IF file.version_count > 1 && !is_other_version %]<span id="[% 'version_toggle_' _ file.id %]">⏷ </span>[% END %]
+       [% file.version _ '/' _ file.version_count %]
+       [% L.hidden_tag("version[]", file.version) %]
+      </td>
+      <td>[% file.mtime_as_timestamp_s %]</td>
       <td>
        <a href="controller.pl?action=File/download&id=[% file.id %][%- IF file.version %]&version=[%- file.version %][%- END %]">
         <span id="[% "filename_" _ file.id %][%- IF file.version %]_[% file.version %][%- END %]">[% file.file_name %]</span>
index 3db4c4b..3a6f126 100644 (file)
@@ -18,8 +18,7 @@
   <input type="hidden" name="callback" value="[% HTML.escape(callback) %]">
   <input type="hidden" name="POPUP_MODE" value="[% HTML.escape(POPUP_MODE) %]">
 
-  <p>
-   <table>
+  <table>
     <tr>
      <td valign="top">[% 'Follow-Up for user' | $T8 %]</td>
      <td valign="top">
@@ -48,8 +47,7 @@
      <td valign="right" align="top">[% 'Body' | $T8 %]</td>
      <td align="top"><textarea cols="50" rows="10" name="body">[% HTML.escape(body) %]</textarea></td>
     </tr>
-   </table>
-  </p>
+  </table>
 
  [%- IF POPUP_MODE %]
   <p>
    <input type="submit" class="submit" onclick="window.close()" value="[% 'Cancel' | $T8 %]">
   </p>
 
-  [%- IF FOLLOW_UPS.size %]
+  [%- IF FOLLOW_UPS_PENDING.size %]
   <hr height="3" noshade>
 
   <h2>[% 'Existing pending follow-ups for this item' | $T8 %]</h2>
 
-  <p>
-   <table>
+  <table>
     <tr>
      <th class="listheading">[% 'Follow-Up Date' | $T8 %]</th>
      <th class="listheading">[% 'Subject' | $T8 %]</th>
@@ -76,7 +73,7 @@
      <th class="listheading">[% 'Follow-up for' | $T8 %]</th>
     </tr>
 
-    [%- FOREACH row = FOLLOW_UPS %]
+    [%- FOREACH row = FOLLOW_UPS_PENDING %]
     <tr class="listrow[% loop.count % 2 %]">
      <td valign="top">[% HTML.escape(row.follow_up_date) %]</td>
      <td valign="top"><a href="fu.pl?action=edit&id=[% HTML.escape(row.id) %][% IF POPUP_MODE %]&POPUP_MODE=1[% END %]">[% HTML.escape(row.subject) %]</a></td>
      <td valign="top">[% HTML.escape(row.created_for_user_name) %]</td>
     </tr>
     [%- END %]
-   </table>
-  </p>
+  </table>
   [%- END %]
+
+  [%- IF FOLLOW_UPS_DONE.size %]
+  <hr height="3" noshade>
+
+  <h2>[% 'Existing finished follow-ups for this item' | $T8 %]</h2>
+
+  <table>
+    <tr>
+     <th class="listheading">[% 'Follow-Up Date' | $T8 %]</th>
+     <th class="listheading">[% 'Subject' | $T8 %]</th>
+     <th class="listheading">[% 'Created by' | $T8 %]</th>
+     <th class="listheading">[% 'Follow-up for' | $T8 %]</th>
+    </tr>
+
+    [%- FOREACH row = FOLLOW_UPS_DONE %]
+    <tr class="listrow[% loop.count % 2 %]">
+     <td valign="top">[% HTML.escape(row.follow_up_date) %]</td>
+     <td valign="top"><a href="fu.pl?action=edit&id=[% HTML.escape(row.id) %][% IF POPUP_MODE %]&POPUP_MODE=1[% END %]">[% HTML.escape(row.subject) %]</a></td>
+     <td valign="top">[% HTML.escape(row.created_by_name) %]</td>
+     <td valign="top">[% HTML.escape(row.created_for_user_name) %]</td>
+    </tr>
+    [%- END %]
+  </table>
   [%- END %]
 
+ [%- END %]
+
   [%- FOREACH row = LINKS %]
   <input type="hidden" name="trans_id_[% loop.count %]"   value="[% HTML.escape(row.trans_id) %]">
   <input type="hidden" name="trans_type_[% loop.count %]" value="[% HTML.escape(row.trans_type) %]">
index 3187637..eb74675 100644 (file)
@@ -25,3 +25,9 @@
   <a onclick="$('#edit_longdescription_dialog').dialog('close');" href="#">[% LxERP.t8("Abort") %]</a>
  </p>
 </div>
+
+<script>
+  $(function() {
+    kivi.SalesPurchase.longdescription_dialog_size_percentage = "[% longdescription_dialog_size_percentage %]";
+  });
+</script>
index 2db858d..a25cc7e 100644 (file)
@@ -28,8 +28,8 @@
        [%- END %]
       </td>
       <td>
-       [%- IF mail_string.search('preset') %]
-        <textarea name="translation__[% language.id %]__[% mail_string %]" rows="4" cols="60">[% HTML.escape(language.$mail_string) %]</textarea>
+       [%- IF mail_string.search('preset') && !mail_string.search('subject')%]
+        <textarea name="translation__[% language.id %]__[% mail_string %]" rows="4" cols="60" class="texteditor">[% HTML.escape(language.$mail_string) %]</textarea>
        [%- ELSE %]
         <input name="translation__[% language.id %]__[% mail_string %]" size="40" value="[% HTML.escape(language.$mail_string) %]">
        [%- END %]
index dad0d69..8dd130a 100644 (file)
@@ -42,6 +42,9 @@
   <li><a href="#ui-tabs-docs">[% 'Documents' | $T8 %]</a></li>
   <li><a href="controller.pl?action=File/list&file_type=attachment&object_type=gl_transaction&object_id=[% HTML.url(id) %]">[% 'Attachments' | $T8 %]</a></li>
 [%- END %]
+  [%- IF AUTH.assert('record_links', 1) %]
+  <li><a href="controller.pl?action=RecordLinks/ajax_list&object_model=GLTransaction&object_id=[% HTML.url(id) %]">[% 'Linked Records' | $T8 %]</a></li>
+  [%- END %]
 [%- END %]
  </ul>
 
@@ -67,7 +70,7 @@
         </tr>
         <tr>
           <th align="right">[% 'Reference' | $T8 %]</th>
-          <td>[% L.input_tag('reference', reference,  size=20, readonly=readonly) %]</td>
+          <td>[% L.input_tag('reference', reference,  style='width:330px', readonly=readonly) %]</td>
           <th align="right">[% 'Transdate' | $T8 %]</th>
           <td>[% L.date_tag('transdate', transdate, readonly=readonly) %]</td>
         </tr>
            SET departments_style = "style='visibility:hidden'" IF ALL_DEPARTMENTS.size == 0 %]
         <tr>
           <th [%- departments_style -%]align="right">[% 'Department' | $T8 %]</th>
-          <td [%- departments_style -%]>[% L.select_tag('department_id', ALL_DEPARTMENTS, default = department_id, title_key = 'description', with_empty = 1) %]</td>
+          <td [%- departments_style -%]>[% L.select_tag('department_id', ALL_DEPARTMENTS, default = department_id, title_key = 'description', with_empty = 1, style = 'width:334px') %]</td>
           <th align=right>[% 'Tax point' | $T8 %]</th>
           <td>[% L.date_tag('tax_point', tax_point) %]</td>
         </tr>
         <tr>
-          <th align="right">[% 'Description' | $T8 %]</th>
-          <td>[% L.areainput_tag('description', description, cols=50, readonly=readonly) %]</td>
+          <th align="right">[% 'Transaction description' | $T8 %]</th>
+          <td>[% L.input_tag("transaction_description", transaction_description, style='width:330px') %]</td>
           <th align=right>[% 'Delivery Date' | $T8 %]</th>
           <td>[% L.date_tag('deliverydate', deliverydate) %]</td>
         </tr>
+        <tr>
+          <th align="right">[% 'Description' | $T8 %]</th>
+          <td>[% L.areainput_tag('description', description, cols=50, style='width:330px', readonly=readonly) %]</td>
+        </tr>
         <tr>
           <th align="right">[%- IF id %][% 'Mitarbeiter' | $T8 %][% END %]</th>
           <td>[%- IF id %][% L.input_tag('employee', employee, size=20, readonly=readonly) %][% END %]</td>
index da3cb7b..e7e1d5b 100644 (file)
           <th align=right>[% 'Notes' | $T8 %]</th>
           <td colspan=3><input name=notes size=40></td>
         </tr>
+        <tr>
+          <th align=right>[% 'Transaction description' | $T8 %]</th>
+          <td>[% L.input_tag("transaction_description", "", size=40) %]</td>
+        </tr>
         <tr>
           <th align=right>[% 'Project Number' | $T8 %]</th>
           <td colspan=3>[% L.select_tag('project_id', ALL_PROJECTS, title_key = 'projectnumber', with_empty = 1) %]</td>
         </tr>
- <tr>
-    <th align=right>[% 'Employee' | $T8 %]</th>
-    <td colspan=3>[% L.select_tag('employee_id', ALL_EMPLOYEES, title_key = 'safe_name', with_empty = 1) %]</td>
-  </tr>
-  <tr>
-    <th align=right>[% 'Filter date by' | $T8 %]</th>
-    <td colspan=3>
-    <input name=datesort class=radio type=radio value=transdate checked> [% 'Transdate' | $T8 %]
-    <input name=datesort class=radio type=radio value=gldate> [% 'Gldate' | $T8 %]
-  </td>
-  </tr>
-  <tr>
-    <th align=right>[% 'From' | $T8 %]</th>
       <tr>
+          <th align=right>[% 'Employee' | $T8 %]</th>
+          <td colspan=3>[% L.select_tag('employee_id', ALL_EMPLOYEES, title_key = 'safe_name', with_empty = 1) %]</td>
+        </tr>
+        <tr>
+          <th align=right>[% 'Filter date by' | $T8 %]</th>
+          <td colspan=3>
+            <input name=datesort class=radio type=radio value=transdate checked> [% 'Transdate' | $T8 %]
+            <input name=datesort class=radio type=radio value=gldate> [% 'Gldate' | $T8 %]
+          </td>
+        </tr>
+        <tr>
+          <th align=right>[% 'From' | $T8 %]</th>
           <td>[% L.date_tag('datefrom') %]</td>
           <th align=right>[% 'To (time)' | $T8 %]</th>
           <td>[% L.date_tag('dateto') %]</td>
                 </td>
               </tr>
               <tr>
-                <table>
-                  <tr>
-                    <td align=right><input name="l_id" class=checkbox type=checkbox value=Y></td>
-                    <td>[% 'ID' | $T8 %]</td>
-                    <td align=right><input name="l_transdate" class=checkbox type=checkbox value=Y checked></td>
-                    <td>[% 'Transdate' | $T8 %]</td>
-                    <td align=right><input name="l_gldate" class=checkbox type=checkbox value=Y checked></td>
-                    <td>[% 'Gldate' | $T8 %]</td>
-                    <td align=right><input name="l_reference" class=checkbox type=checkbox value=Y checked></td>
-                    <td>[% 'Reference' | $T8 %]</td>
-                    <td align=right><input name="l_description" class=checkbox type=checkbox value=Y checked></td>
-                    <td>[% 'Description' | $T8 %]</td>
-                    <td align=right><input name="l_notes" class=checkbox type=checkbox value=Y></td>
-                    <td>[% 'Notes' | $T8 %]</td>
-                  </tr>
-                  <tr>
-                    <td align=right><input name="l_debit" class=checkbox type=checkbox value=Y checked></td>
-                    <td>[% 'Debit' | $T8 %]</td>
-                    <td align=right><input name="l_credit" class=checkbox type=checkbox value=Y checked></td>
-                    <td>[% 'Credit' | $T8 %]</td>
-                    <td align=right><input name="l_source" class=checkbox type=checkbox value=Y checked></td>
-                    <td>[% 'Source' | $T8 %]</td>
-                    <td align=right><input name="l_accno" class=checkbox type=checkbox value=Y checked></td>
-                    <td>[% 'Account' | $T8 %]</td>
-                    [%- IF ALL_DEPARTMENTS %]
+                <td>
+                  <table>
+                    <tr>
+                      <td align=right><input name="l_id" class=checkbox type=checkbox value=Y></td>
+                      <td>[% 'ID' | $T8 %]</td>
+                      <td align=right><input name="l_transdate" class=checkbox type=checkbox value=Y checked></td>
+                      <td>[% 'Transdate' | $T8 %]</td>
+                      <td align=right><input name="l_gldate" class=checkbox type=checkbox value=Y checked></td>
+                      <td>[% 'Gldate' | $T8 %]</td>
+                      <td align=right><input name="l_reference" class=checkbox type=checkbox value=Y checked></td>
+                      <td>[% 'Reference' | $T8 %]</td>
+                      <td align=right><input name="l_description" class=checkbox type=checkbox value=Y checked></td>
+                      <td>[% 'Description' | $T8 %]</td>
+                      <td align=right><input name="l_notes" class=checkbox type=checkbox value=Y></td>
+                      <td>[% 'Notes' | $T8 %]</td>
+                    </tr>
+                    <tr>
+                      <td align=right><input name="l_debit" class=checkbox type=checkbox value=Y checked></td>
+                      <td>[% 'Debit' | $T8 %]</td>
+                      <td align=right><input name="l_credit" class=checkbox type=checkbox value=Y checked></td>
+                      <td>[% 'Credit' | $T8 %]</td>
+                      <td align=right><input name="l_source" class=checkbox type=checkbox value=Y checked></td>
+                      <td>[% 'Source' | $T8 %]</td>
+                      <td align=right><input name="l_accno" class=checkbox type=checkbox value=Y checked></td>
+                      <td>[% 'Account' | $T8 %]</td>
+                      [%- IF ALL_DEPARTMENTS %]
                       <td align=right><input name="l_department" class=checkbox type=checkbox value=Y></td>
                       <td>[% 'Department' | $T8 %]</td>
-                    [%- END %]
-                  </tr>
-                  <tr>
-                    <td align=right><input name="l_projectnumbers" class=checkbox type=checkbox value=Y></td>
-                    <td>[% 'Project Number' | $T8 %]</td>
-                    <td align=right><input name="l_employee" class=checkbox type=checkbox value=Y></td>
-                    <td>[% 'Employee' | $T8 %]</td>
-                  </tr>
-                  <tr>
-                    <td align=right><input name="l_subtotal" class=checkbox type=checkbox value=Y></td>
-                    <td>[% 'Subtotal' | $T8 %]</td>
-                  </tr>
-                </table>
+                      [%- END %]
+                    </tr>
+                    <tr>
+                      <td align=right><input name="l_projectnumbers" class=checkbox type=checkbox value=Y></td>
+                      <td>[% 'Project Number' | $T8 %]</td>
+                      <td align=right><input name="l_employee" class=checkbox type=checkbox value=Y></td>
+                      <td>[% 'Employee' | $T8 %]</td>
+                      <td align=right><input name="l_transaction_description" id="l_transaction_description" class=checkbox type=checkbox value=Y[% IF INSTANCE_CONF.get_require_transaction_description_ps %] checked[% END %]></td>
+                      <td>[% 'Transaction description' | $T8 %]</td>
+                    </tr>
+                    <tr>
+                      <td align=right><input name="l_subtotal" class=checkbox type=checkbox value=Y></td>
+                      <td>[% 'Subtotal' | $T8 %]</td>
+                    </tr>
+                  </table>
+                </td>
               </tr>
             </table>
         </tr>
index 6726c8b..1110839 100644 (file)
     </td>
   </tr>
     <script type='text/javascript'>
-     $('#is_set_to_paid_missing').click(function(){ $('input[name^="paid_"]:last').val('[% LxERP.format_amount(paid_missing, 2) %]') });
+     $('#is_set_to_paid_missing').click(function(){ $('input[name^="paid_"]:last').val("[% LxERP.format_amount(paid_missing, 2) %]") });
     </script>
index 93a0fb8..8072df3 100644 (file)
     </td>
   </tr>
     <script type='text/javascript'>
-     $('#is_set_to_paid_missing').click(function(){ $('input[name^="paid_"]:last').val('[% LxERP.format_amount(paid_missing, 2) %]') });
+     $('#is_set_to_paid_missing').click(function(){ $('input[name^="paid_"]:last').val("[% LxERP.format_amount(paid_missing, 2) %]") });
     </script>
index 7d4c608..7c749cf 100644 (file)
                  [%- L.checkbox_tag('direct_debit', 'checked', direct_debit) %]
                </td>
              </tr>
+[%- IF INSTANCE_CONF.get_create_qrbill_invoices > 0 %]
+             <tr>
+               <th align="right">[% 'QR bill without amount' | $T8 %]</th>
+               <td>
+                 [%- L.checkbox_tag('qrbill_without_amount', 'checked', qrbill_without_amount) %]
+               </td>
+             </tr>
+[%- END %]
            </table>
          </td>
         </tr>
     </table>
    </td>
   </tr>
-
-[% PROCESS 'is/_payments.html' %]
+[% IF is_type_normal_invoice OR  is_type_credit_note %]
+  [% PROCESS 'is/_payments.html' %]
+[% END %]
  </table>
 </div>
 [% PROCESS 'webdav/_list.html' %]
 <input type="hidden" name="customer_discount" value="[% customer_discount %]">
 <input type="hidden" name="gldate" value="[% gldate %]">
 
+[%- IF INSTANCE_CONF.get_create_qrbill_invoices <= 0 %]
+ <input type="hidden" name="qrbill_without_amount" value="[% qrbill_without_amount %]">
+[%- END %]
+
 <div id="shipto_inputs" class="hidden">
  [%- PROCESS 'common/_ship_to_dialog.html' cvars=shipto_cvars %]
 </div>
index e61b175..c870191 100644 (file)
@@ -18,6 +18,7 @@
 <input type="hidden" name="follow_up_trans_info_1" id="follow_up_trans_info_1" value="[% HTML.escape(follow_up_trans_info) %]">
 <input type="hidden" name="follow_up_rowcount" id="follow_up_rowcount" value="1">
 <input type="hidden" name="lastmtime" id="lastmtime" value="[% HTML.escape(lastmtime) %]">
+<input type="hidden" name="already_printed_flag" id="already_printed_flag" value="0">
 
 <h1>[% title %]</h1>
 
@@ -34,9 +35,8 @@
 [%- END %]
 [%- IF id %]
   [%- IF INSTANCE_CONF.get_doc_storage %]
-  [% object_type = is_type_credit_note? 'credit_note' : 'invoice' %]
-  <li><a href="controller.pl?action=File/list&file_type=document&object_type=[% object_type %]&object_id=[% HTML.url(id) %]">[% 'Documents' | $T8 %]</a></li>
-  <li><a href="controller.pl?action=File/list&file_type=attachment&object_type=[% object_type %]&object_id=[% HTML.url(id) %]">[% 'Attachments' | $T8 %]</a></li>
+  <li><a href="controller.pl?action=File/list&file_type=document&object_type=[% type %]&object_id=[% HTML.url(id) %]">[% 'Documents' | $T8 %]</a></li>
+  <li><a href="controller.pl?action=File/list&file_type=attachment&object_type=[% type %]&object_id=[% HTML.url(id) %]">[% 'Attachments' | $T8 %]</a></li>
   [%- END %]
   [%- IF AUTH.assert('record_links', 1) %]
   <li><a href="controller.pl?action=RecordLinks/ajax_list&object_model=Invoice&object_id=[% HTML.url(id) %]">[% 'Linked Records' | $T8 %]</a></li>
@@ -57,6 +57,7 @@
           <td>
            [% P.customer_vendor.picker("customer_id", customer_id, type="customer", style="width: 250px", class="initial_focus", onchange="\$('#update_button').click()") %]
            [% L.button_tag("show_vc_details('customer')", LxERP.t8('Details (one letter abbreviation)')) %]
+           [% P.link_tag('controller.pl?action=CustomerVendor/edit&db=customer&id=' _ customer_id, LxERP.t8('Edit'), target="_blank", title=LxERP.t8('Open in new window')) %]
            [% L.hidden_tag("previous_customer_id", customer_id) %]
            [% L.hidden_tag("customer_pricegroup_id", customer_pricegroup_id) %]
           </td>
            [% L.button_tag("kivi.SalesPurchase.edit_custom_shipto()", LxERP.t8("Custom shipto")) %]
           </td>
         </tr>
+
+[%- IF customer_obj.additional_billing_addresses.as_list.size %]
+        <tr>
+          <th align="right">[% 'Custom Billing Address' | $T8 %]</th>
+          <td>
+            [% L.select_tag('billing_address_id', customer_obj.additional_billing_addresses,
+                            with_empty=1, default=billing_address_id, value_key='id', title_key='displayable_id', style='width: 250px') %]
+          </td>
+        </tr>
+[%- END %]
+
         <tr>
           <td align="right">[% 'Credit Limit' | $T8 %]</td>
           <td>
 [%- IF is_type_credit_note %]
         <tr>
           <th align="right" nowrap>[% 'Credit Note Number' | $T8 %]</th>
-          <td colspan="3"><input size='11' name="invnumber" id="invnumber" value="[% HTML.escape(invnumber) %]"></td>
+          <td colspan="3">
+[%- IF INSTANCE_CONF.get_sales_purchase_record_numbers_changeable %]
+            [% L.input_tag("invnumber", invnumber, size="11") %]
+[%- ELSIF id %]
+            [% L.hidden_tag("invnumber", invnumber) %]
+            [% HTML.escape(invnumber) %]
+[%- ELSE %]
+            [% LxERP.t8("will be set upon posting") %]
+[%- END %]
+          </td>
         </tr>
         <tr>
           <th align="right" nowrap>[% 'Invoice Number' | $T8 %]</th>
 [%- ELSE %]
         <tr>
           <th align="right" nowrap>[% 'Invoice Number' | $T8 %]</th>
-          <td colspan="3"><input size='11' name="invnumber" id="invnumber" value="[% HTML.escape(invnumber) %]"></td>
+          <td colspan="3">
+[%- IF INSTANCE_CONF.get_sales_purchase_record_numbers_changeable %]
+          [% L.input_tag("invnumber", invnumber, size="11") %]
+[%- ELSIF id %]
+            [% L.hidden_tag("invnumber", invnumber) %]
+            [% HTML.escape(invnumber) %]
+[%- ELSE %]
+            [% LxERP.t8("will be set upon posting") %]
+[%- END %]
+          </td>
         </tr>
         <tr>
           <th align="right">[% 'Invoice Date' | $T8 %]</th>
   <script type="text/javascript">
    <!--
      $('document').ready(function(){
+[% IF INSTANCE_CONF.get_invoice_prevent_browser_back %]
+       function disableBack() { window.history.forward() };
+       window.onload = disableBack();
+       window.onpageshow = function(evt) { if (evt.persisted) disableBack() };
+[% END %]
+
 [% IF resubmit && is_format_html %]
        window.open('about:blank','Beleg');
        document.invoice.target = 'Beleg';
        kivi.SalesPurchase.show_print_dialog();
        kivi.SalesPurchase.print_record();
 [% ELSIF resubmit %]
-       kivi.SalesPurchase.show_print_dialog();
-       kivi.SalesPurchase.print_record();
+       if ($('#already_printed_flag').val() === "0") {
+         kivi.SalesPurchase.show_print_dialog();
+         kivi.SalesPurchase.print_record();
+         $('#already_printed_flag').val("1");
+       }
 [% ELSIF creditwarning != '' %]
        alert('[% 'Credit Limit exceeded!!!' | $T8 %]');
 [% ELSE %]
index ebfafeb..94aeb5b 100644 (file)
@@ -8,6 +8,18 @@
 [%- END -%]
 
  <form name="Form" action="oe.pl" method="post">
+  [%- IF popup_dialog -%]
+    [% L.button_tag(popup_js_assign_function, LxERP.t8('Assign')) %]
+    [% L.button_tag(popup_js_close_function, LxERP.t8('Cancel')) %]
+
+  [%- ELSE -%]
+    [% L.hidden_tag('action', 'save_periodic_invoices_config') %]
+
+    <p>
+     [% L.submit_tag('', LxERP.t8('Assign')) %]
+     [% L.submit_tag('', LxERP.t8('Cancel'), onclick => "self.close(); return false;") %]
+    </p>
+  [%- END -%]
 
   <p>
    <table border="0">
 
     <tr>
      <th align="right" valign="top">[%- LxERP.t8("Message") %]</th>
-     <td valign="top">[% L.textarea_tag("email_body", config.email_body, disabled=!config.send_email, rows=8, style=style) %]</td>
+     <td valign="top">[% L.textarea_tag("email_body", config.email_body, disabled=!config.send_email, rows=8, style=style, class="texteditor texteditor-space-for-toolbar") %]</td>
     </tr>
    </table>
   </p>
   <p>(2): [% LxERP.t8("If missing then the start date will be used.") %]</p>
   <p>(3): [% LxERP.t8("Multiple addresses can be entered separated by commas.") %]</p>
   <p>(4): [% LxERP.t8("If left empty the default sender from the kivitendo configuration will be used (key 'email_from' in section 'periodic_invoices'; current value: #1).", HTML.escape(LXCONFIG.periodic_invoices.email_from)) %]</p>
-
-  [%- IF popup_dialog -%]
-    [% L.button_tag(popup_js_assign_function, LxERP.t8('Assign')) %]
-    [% L.button_tag(popup_js_close_function, LxERP.t8('Cancel')) %]
-
-  [%- ELSE -%]
-    [% L.hidden_tag('action', 'save_periodic_invoices_config') %]
-
-    <p>
-     [% L.submit_tag('', LxERP.t8('Assign')) %]
-     [% L.submit_tag('', LxERP.t8('Cancel'), onclick => "self.close(); return false;") %]
-    </p>
-  [%- END -%]
  </form>
 
  <script type="text/javascript">
       $('#email_recipient_address').prop('disabled', disabled);
       $('#email_sender').prop('disabled', disabled);
       $('#email_subject').prop('disabled', disabled);
-      $('#email_body').prop('disabled', disabled);
+      $('#email_body').data('ckeditorInstance').setReadOnly(disabled);
     }
     -->
  </script>
index 2390718..002fa55 100644 (file)
                       [% L.button_tag("kivi.SalesPurchase.edit_custom_shipto()", LxERP.t8("Custom shipto")) %]
                     </td>
                   </tr>
+
+[%- IF is_sales && vc_obj.additional_billing_addresses.as_list.size %]
+                  <tr>
+                    <th align="right">[% 'Custom Billing Address' | $T8 %]</th>
+                    <td>
+                      [% L.select_tag('billing_address_id', vc_obj.additional_billing_addresses,
+                                      with_empty=1, default=billing_address_id, value_key='id', title_key='displayable_id', style='width: 250px') %]
+                    </td>
+                  </tr>
+[%- END %]
+
 [%- IF is_order %]
                   <tr>
                     <td align="right">[% 'Credit Limit' | $T8 %]</td>
 [%- IF is_order %]
                   <tr>
                     <th width="70%" align="right" nowrap>[% 'Order Number' | $T8 %]</th>
-                    <td><input name="ordnumber" id="ordnumber" size="11" value="[% HTML.escape(ordnumber) %]"></td>
+                    <td>
+[%- IF INSTANCE_CONF.get_sales_purchase_record_numbers_changeable %]
+                      [% L.input_tag("ordnumber", ordnumber, size="11") %]
+[%- ELSIF id %]
+                      [% HTML.escape(ordnumber) %]
+                      [% L.hidden_tag("ordnumber", ordnumber) %]
+[%- ELSE %]
+                      [% LxERP.t8("will be set upon saving") %]
+[%- END %]
+                    </td>
                   </tr>
 [%- END %]
                   <tr>
                     <th width="70%" align="right" nowrap>[% IF is_req_quo %][% 'RFQ Number' | $T8 %][% ELSE %][% 'Quotation Number' | $T8 %][% END %]</th>
-                    <td><input name="quonumber" id="quonumber" size="11" value="[% HTML.escape(quonumber) %]"></td>
+                    <td>
+[%- IF is_order || INSTANCE_CONF.get_sales_purchase_record_numbers_changeable %]
+                      [% L.input_tag("quonumber", quonumber, size="11") %]
+[%- ELSIF id %]
+                      [% HTML.escape(quonumber) %]
+                      [% L.hidden_tag("quonumber", quonumber) %]
+[%- ELSE %]
+                      [% LxERP.t8("will be set upon saving") %]
+[%- END %]
+                    </td>
                   </tr>
 [%- IF is_order %]
                   <tr>
index b24e9dd..7f85ff3 100644 (file)
      <th align="right">[% 'Internal Notes' | $T8 %]</th>
      <td>[% L.input_tag('intnotes', '', style=style) %]</td>
     </tr>
+    <tr>
+     <th align="right">[% 'Phone Notes' | $T8 %]</th>
+     <td>[% L.input_tag('phone_notes', '', style=style) %]</td>
+    </tr>
+    [%- IF type == 'sales_order' %]
+    <tr>
+     <th align="right">[% 'Full Text' | $T8 %]</th>
+     <td>[% L.input_tag('fulltext', '', style=style) %]</td>
+    </tr>
+    [%- END %]
     <tr>
      <th align="right">[% IF is_order %][% 'Order Date' | $T8 %][% ELSE %][% 'Quotation Date' | $T8 %][% END %] [% 'From' | $T8 %]</th>
      <td>
index c3ff986..82bc2f1 100644 (file)
@@ -15,7 +15,9 @@
 
 <div id="shipto_dialog" class="hidden"></div>
 
-<form method="post" action="controller.pl" id="order_form">
+<form method="post" action="controller.pl" id="order_form"
+      data-transport-cost-reminder-article-id="[% HTML.escape(transport_cost_reminder_article.id) %]"
+      data-transport-cost-reminder-article-description="[% HTML.escape(transport_cost_reminder_article.displayable_name) %]">
   [% L.hidden_tag('callback',             FORM.callback) %]
   [% L.hidden_tag('type',                 FORM.type) %]
   [% L.hidden_tag('id',                   SELF.order.id) %]
@@ -36,6 +38,9 @@
 [%- IF SELF.order.id %]
       <li><a href="controller.pl?action=RecordLinks/ajax_list&object_model=Order&object_id=[% HTML.url(SELF.order.id) %]">[% 'Linked Records' | $T8 %]</a></li>
 [%- END %]
+[% IF SELF.order.id %]
+      <li><a href="#ui-tabs-phone-notes">[% 'Phone Notes' | $T8 %]<span id="num_phone_notes">[%- num_phone_notes ? ' (' _ num_phone_notes _ ')' : '' -%]</span></a></li>
+[% END %]
     </ul>
 
     [% PROCESS "order/tabs/basic_data.html" %]
     <div id="ui-tabs-1">
       [%- LxERP.t8("Loading...") %]
     </div>
-
+[% IF SELF.order.id %]
+    <div id="ui-tabs-phone-notes">
+      [% PROCESS "order/tabs/phone_notes.html" %]
+    </div>
+[% END %]
     <div id="shipto_inputs" class="hidden">
       [%- PROCESS 'common/_ship_to_dialog.html'
         vc_obj=SELF.order.customervendor
index 1b1bf60..8f75b6f 100644 (file)
@@ -29,7 +29,6 @@
           [%- SET PARAM_KEY = SELF.cv == "customer" ? 'with_customer_partnumber' : 'with_makemodel' -%]
           [%- SET PARAM_VAL = SELF.search_cvpartnumber -%]
           [% P.part.picker('add_item.parts_id', SELF.created_part, style='width: 300px', class="add_item_input",
-                            fat_set_item=1,
                             multiple_pos_input=1,
                             action={set_multi_items='kivi.Order.add_multi_items'},
                             classification_id=SELF.part_picker_classification_ids.as_list.join(','),
           [% L.input_tag('add_item.qty_as_number', '', size = 5, class="add_item_input numeric") %]
           [% L.hidden_tag('add_item.unit', SELF.created_part.unit, class="add_item_input") %]
         </td>
-        [%- SET price = LxERP.format_amount(((SELF.type == 'sales_quotation' || SELF.type == 'sales_order') ? SELF.created_part.sellprice : SELF.created_part.lastcost), -2) -%]
-        <td>[% L.input_tag('add_item.sellprice_as_number', price, size = 10, class="add_item_input numeric") %]</td>
-        <td>[% L.input_tag('add_item.discount_as_percent', '', size = 5, class="add_item_input numeric") %]</td>
+        [%- SET price = '' %]
+        [%- IF SELF.created_part %]
+          [%- SET price = LxERP.format_amount(((SELF.type == 'sales_quotation' || SELF.type == 'sales_order') ? SELF.created_part.sellprice : SELF.created_part.lastcost), -2) -%]
+        [%- END %]
+        <td>[% L.input_tag('add_item.sellprice_as_number', price, size = 10, class="add_item_input numeric tooltipster-html") %]</td>
+        <td>[% L.input_tag('add_item.discount_as_percent', '', size = 5, class="add_item_input numeric tooltipster-html") %]</td>
         <td>[% L.button_tag('kivi.Order.add_item()', LxERP.t8('Add part')) %]</td>
       </tr>
     </tbody>
index c4bcda0..4314902 100644 (file)
@@ -17,6 +17,7 @@
             <td>
               [% P.customer_vendor.picker("order.${SELF.cv}" _ '_id', SELF.order.$cv_id, type=SELF.cv, style='width: 300px') %]
               [% P.button_tag("kivi.Order.show_vc_details_dialog()", LxERP.t8("Details (one letter abbreviation)")) %]
+              [% P.link_tag(SELF.url_for(controller='CustomerVendor', action='edit', 'id'=SELF.order.$cv_id, 'db'=SELF.cv), LxERP.t8('Edit'), target="_blank", title=LxERP.t8('Open in new window')) %]
             </td>
           </tr>
 
             </td>
           </tr>
 
+          [%- IF SELF.cv == "customer" %]
+          <tr id="billing_address_row"[% IF !SELF.order.customer.additional_billing_addresses.as_list.size %] style="display:none"[% END %]>
+            <th align="right">[% 'Custom Billing Address' | $T8 %]</th>
+            <td>
+              [% L.select_tag('order.billing_address_id',
+                               SELF.order.customer.additional_billing_addresses,
+                               default=SELF.order.billing_address_id,
+                               title_key='displayable_id',
+                               value_key='id',
+                               with_empty=1,
+                               style='width: 300px') %]
+            </td>
+          </tr>
+          [%- END %]
+
           [%- PROCESS order/tabs/_business_info_row.html SELF=SELF %]
 
           <tr>
           [%- IF (SELF.type == "sales_order" || SELF.type == "purchase_order") -%]
           <tr>
             <th width="70%" align="right" nowrap>[% 'Order Number' | $T8 %]</th>
-            <td>[% L.input_tag('order.ordnumber', SELF.order.ordnumber, size = 11, onchange='kivi.Order.set_number_in_title(this)') %]</td>
+            <td>
+              [%- IF INSTANCE_CONF.get_sales_purchase_record_numbers_changeable %]
+                [% L.input_tag('order.ordnumber', SELF.order.ordnumber, size = 11, onchange='kivi.Order.set_number_in_title(this)') %]
+              [%- ELSIF SELF.order.id %]
+                [% HTML.escape(SELF.order.ordnumber) %]
+                [% L.hidden_tag("order.ordnumber", SELF.order.ordnumber) %]
+              [% ELSE %]
+                [% LxERP.t8("will be set upon saving") %]
+              [%- END %]
+            </td>
           </tr>
           [%- END -%]
 
           [%- END -%]
           <tr>
             <th width="70%" align="right" nowrap>[% quo_nr_txt | $T8 %]</th>
-            [%- IF (SELF.type == "sales_order" || SELF.type == "purchase_order") -%]
-              <td>[% L.input_tag('order.quonumber', SELF.order.quonumber, size = 11) %]</td>
-            [%- ELSE -%]
-              <td>[% L.input_tag('order.quonumber', SELF.order.quonumber, size = 11, onchange='kivi.Order.set_number_in_title(this)') %]</td>
-            [%- END -%]
+            <td>
+              [%- IF (SELF.type == "sales_order" || SELF.type == "purchase_order") -%]
+                [% L.input_tag('order.quonumber', SELF.order.quonumber, size = 11) %]
+              [%- ELSIF INSTANCE_CONF.get_sales_purchase_record_numbers_changeable %]
+                [% L.input_tag('order.quonumber', SELF.order.quonumber, size = 11, onchange='kivi.Order.set_number_in_title(this)') %]
+              [%- ELSIF SELF.order.id %]
+                [% HTML.escape(SELF.order.quonumber) %]
+                [% L.hidden_tag("order.quonumber", SELF.order.quonumber) %]
+              [% ELSE %]
+                [% LxERP.t8("will be set upon saving") %]
+              [%- END %]
+            </td>
           </tr>
 
           [%- IF (SELF.type == "sales_order" || SELF.type == "purchase_order") -%]
diff --git a/templates/webpages/order/tabs/phone_notes.html b/templates/webpages/order/tabs/phone_notes.html
new file mode 100644 (file)
index 0000000..b1d2117
--- /dev/null
@@ -0,0 +1,47 @@
+[%- USE T8 %]
+[%- USE HTML %]
+[%- USE L %]
+[%- USE LxERP %]
+[%- USE P %]
+
+<div id="phone-notes">
+ [% IF ( SELF.order.phone_notes && SELF.order.phone_notes.size ) %]
+  <table>
+    <tr>
+      <th class="listheading">[% 'Subject' | $T8 %]</th>
+      <th class="listheading">[% 'Created on' | $T8 %]</th>
+      <th class="listheading">[% 'Created by' | $T8 %]</th>
+    </tr>
+
+    [%- FOREACH row = SELF.order.phone_notes %]
+     <tr class="listrow">
+       <td>[% P.link_tag('#', row.subject, onclick="kivi.Order.load_phone_note(" _ HTML.url(row.id) _ ", '" _ HTML.escape(row.subject) _ "', '" _ HTML.escape(row.body) _ "')") %]</td>
+       <td>[% row.itime.to_kivitendo | html %]</td>
+       <td>[% row.employee.safe_name | html %]</td>
+     </tr>
+    [% END %]
+  </table>
+ [% END %]
+
+  <h2 id='phone_note_edit_text'>[% 'Add note' | $T8 %]</h2>
+
+  [% L.hidden_tag('phone_note.id') %]
+
+  <table>
+    <tr>
+      <td valign="right">[% 'Subject' | $T8 %]</td>
+      <td>[% L.input_tag('phone_note.subject', '', size = 50) %]</td>
+    </tr>
+    <tr>
+      <td valign="right" align="top">[% 'Body' | $T8 %]</td>
+      <td align="top">[% L.textarea_tag('phone_note.body', '', cols = 50 rows = 10) %]</td>
+    </tr>
+  </table>
+
+ <p>
+   [% P.button_tag("kivi.Order.save_phone_note()",   LxERP.t8('Save')) %]
+   [% P.button_tag("kivi.Order.delete_phone_note()", LxERP.t8('Delete'), id = 'phone_note_delete_button', style='display:none') %]
+   [% P.button_tag("kivi.Order.cancel_phone_note()", LxERP.t8('Cancel')) %]
+ </p>
+
+</div>
index ba18da2..a9fa531 100644 (file)
@@ -19,7 +19,7 @@
             <table id="ic3">
              <tr>
               <th align="right">[% 'Part Number' | $T8 %]</th>
-              <td>[% L.input_tag("part.partnumber", SELF.part.partnumber, size=40, class="initial_focus") %]</td>
+              <td>[% L.input_tag("part.partnumber", SELF.part.partnumber, size=40, class="initial_focus", "data-validate"="trimmed_whitespaces") %]</td>
              </tr>
              <tr>
               <th align="right">[% 'Part Classification' | $T8 %]</th>
@@ -33,7 +33,7 @@
              </tr>
              <tr>
                <th align="right">[% 'EAN-Code' | $T8 %]</th>
-               <td>[% L.input_tag("part.ean", SELF.part.ean, size=40) %]</td>
+               <td>[% L.input_tag("part.ean", SELF.part.ean, size=40, "data-validate"="trimmed_whitespaces") %]</td>
              </tr>
              <tr>
               [%- IF SELF.all_partsgroups.size %]
       <table id="ic6">
        <tr>
         <th align="right" nowrap>[% 'Image' | $T8 %]</th>
-        <td>[% L.input_tag("part.image", SELF.part.image, size=40) %]</td>
+        <td>[% L.input_tag("part.image", SELF.part.image, size=40, "data-validate"="trimmed_whitespaces") %]</td>
         <th align="right" nowrap>[% 'Microfiche' | $T8 %]</th>
-        <td>[% L.input_tag("part.microfiche", SELF.part.microfiche, size=20) %]</td>
+        <td>[% L.input_tag("part.microfiche", SELF.part.microfiche, size=20, "data-validate"="trimmed_whitespaces") %]</td>
        </tr>
        <tr>
         <th align="right" nowrap>[% 'Drawing' | $T8 %]</th>
-        <td>[% L.input_tag("part.drawing", SELF.part.drawing, size=40) %]</td>
+        <td>[% L.input_tag("part.drawing", SELF.part.drawing, size=40, "data-validate"="trimmed_whitespaces") %]</td>
        </tr>
       </table>
      </td>
index 051a230..3c65b4d 100644 (file)
    <th>[% LxERP.t8("Action") %]</th>
   </tr>
   </thead>
-  [% # L.dump(SELF.part) %]
+  [% L.dump(SELF.part) %]
   [%- FOREACH shop_part = SELF.part.shop_parts %]
   [% IF !shop_part.shop.obsolete %]
+
   <tr class="listrow">
    <td>[% HTML.escape( shop_part.shop.description ) %]</td>
    <td>[% L.html_tag('span', shop_part.active, id => 'shop_part_active_' _ shop_part.id ) %]</td>
-   <td>[% L.html_tag('span', shop_part.shop_description, id => 'shop_part_description_' _ shop_part.id ) %]</td>
+   <td>
+    [% IF shop_part.shop.use_part_longdescription %]
+      [% L.html_tag('span', shop_part.part.notes, id => 'shop_part_description_' _ shop_part.id ) %]
+    [% ELSE %]
+      [% L.html_tag('span', shop_part.shop_description, id => 'shop_part_description_' _ shop_part.id ) %]
+    [% END %]
+  </td>
    <td>[% L.html_tag('span',LxERP.t8(), id => 'active_price_source_' _ shop_part.id) %] </td>
    <td>[% L.html_tag('span','Price', id => 'price_' _ shop_part.id) %]</td>
    <td>[% L.html_tag('span','Stock', id => 'stock_' _ shop_part.id) %]</td>
index d5bb5b8..ee132ef 100644 (file)
@@ -21,7 +21,6 @@
      <li><a href="#invoice_permissions">[% 'Permissions for invoices' | $T8 %]</a></li>
     [%- END %]
     [%- IF SELF.project.id %]
-    <li><a href="#project_details">[% 'Project Details' | $T8 %]</a></li>
       [%- IF INSTANCE_CONF.get_doc_storage %]
         <li><a href="controller.pl?action=File/list&file_type=attachment&object_type=project&object_id=[% SELF.project.id %]">[% 'Attachments' | $T8 %]</a></li>
       [%- END %]
index 04346b5..d9b0209 100644 (file)
                        style=style) %]</td>
   </tr>
 
+  <tr>
+   <td>[%- LxERP.t8("Record number") %]:</td>
+   <td>[% L.input_tag('number', '', style=style) %]</td>
+  </tr>
+
   <tr>
    <td>[%- LxERP.t8("Customer/Vendor Number") %]:</td>
    <td>[% L.input_tag('vc_number', is_sales ? SELF.object.customer.customernumber : SELF.object.vendor.vendornumber, style=style) %]</td>
index af75628..54166f1 100644 (file)
@@ -1,4 +1,4 @@
-[%- USE HTML -%][%- USE LxERP -%]
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%]
 <div id="basic_settings" class="basic-settings-context-menu">
  <h2>
   [% IF SELF.requirement_spec.is_template %]
   [% FOREACH var = cvars %]
    <tr class="listrow">
     <td>[% HTML.escape(var.config.description) %]</td>
-    <td>[% HTML.escape(var.value_as_text) %]</td>
+    <td>
+      [%- IF var.config.type == 'htmlfield' -%]
+        [%- L.restricted_html(var.value_as_text) -%]
+      [%- ELSE -%]
+        [%- HTML.escape(var.value_as_text) -%]
+      [%- END -%]
+    </td>
    </tr>
   [% END %]
 
index 7f55550..da045f1 100644 (file)
             <div style="height: 125px; overflow:auto;">
               <table>
                 <tr class="listheading">
-                  <th colspan="7">Customer Proposals</td>
+                  <th colspan="7">[% 'Customer Proposals' | $T8 %]</td>
                 </tr>
                 [% FOREACH prop = PROPOSALS %][% IF prop.order_lock %][% SET orderlock_class = 'style="background:rgba(232, 32, 23, 0.2);"' %][% ELSE %][% SET orderlock_class = '' %][% END %]
                 <tr class="listrow" [% orderlock_class %]>
index 9d51997..55e6628 100644 (file)
@@ -15,7 +15,7 @@
           <li>
           [% checked = '' %]
           [% FOREACH cat_row = SELF.shop_part.shop_category %]
-            [% IF cat_row.0 == categorie.id %]
+            [% IF (cat_row.0 == categorie.id) || (SELF.shop_part.shop.connector == 'shopware6' && cat_row == categorie.id) %]
               [% checked = 'checked' %]
             [% END %]
           [% END %]
index 5536ad7..5379532 100644 (file)
     [%- L.hidden_tag("shop_part.part_id", FORM.part_id) %]
     [% END %]
 
+  [% # L.dump(SELF.shop_part.shop) %]
     <table>
     <tr>
      <td>[% LxERP.t8("Description") %]</td>
-     <td colspan="3">[% L.textarea_tag('shop_part.shop_description', SELF.shop_part.shop_description, wrap="soft", style="width: 350px; height: 150px", class="texteditor") %]</td>
+     <td colspan="3">
+       [% IF SELF.shop_part.shop.use_part_longdescription %]
+         [% L.textarea_tag('notes', SELF.shop_part.part.notes, wrap="soft", readonly="readonly", style="width: 350px; height: 150px", class="texteditor") %]
+       [% ELSE %]
+         [% L.textarea_tag('shop_part.shop_description', SELF.shop_part.shop_description, wrap="soft", style="width: 350px; height: 150px", class="texteditor") %]
+       [% END %]
+     </td>
     </tr>
     <tr>
      <td>[% LxERP.t8("Active") %]</td>
      <td>[% L.textarea_tag("shop_part.metatag_description", SELF.shop_part.metatag_description, rows=4) %]</td>
     </tr>
     </table>
-
     [% IF SELF.shop_part.id %]
-    [% L.button_tag("kivi.ShopPart.save_shop_part(" _ SELF.shop_part.id _ ")", LxERP.t8("Save"))  %]</td>
+      [% L.button_tag("kivi.ShopPart.save_shop_part(" _ SELF.shop_part.id _ ")", LxERP.t8("Save"))  %]</td>
     [% ELSE %]
-    [% L.button_tag("kivi.ShopPart.add_shop_part(" _ FORM.part_id _", " _ FORM.shop_id _")", LxERP.t8("Save"))  %]</td>
+      [% L.button_tag("kivi.ShopPart.add_shop_part()", LxERP.t8("Save"))  %]</td>
     [% END %]
-    [% # L.button_tag("kivi.ShopPart.update_partnumber()", LxERP.t8("Update Partnumber"))  %]</td>
-
-    [% # L.hidden_tag("action", "ShopPart/dispatch") %]
-    [% # L.submit_tag('action_update', LxERP.t8('Save')) %]
-
-
   </div>
 </form>
 
index cda1e0b..2f08e72 100644 (file)
     <th align="right">[% 'Port' | $T8 %]</th>
     <td>[%- L.input_tag("shop.port", SELF.shop.port, size=5) %]</td>
   </tr>
+  <tr>
+    <th align="right">[% 'Proxy' | $T8 %]</th>
+    <td>[%- L.input_tag("shop.proxy", SELF.shop.proxy, size=size) %]</td>
+  </tr>
   <tr>
     <th align="right">[% 'Path' | $T8 %]</th>
     <td>[%- L.input_tag("shop.path", SELF.shop.path, size=size) %]</td>
     <th align="right">[% 'Obsolete' | $T8 %]</th>
     <td>[% L.checkbox_tag('shop.obsolete', checked = SELF.shop.obsolete, for_submit=1) %]</td>
   </tr>
+  <tr>
+    <th align="right">[% 'Use Long Description from Parts for Shop Long Description' | $T8 %]</th>
+    <td>[% L.yes_no_tag('shop.use_part_longdescription', SELF.shop.use_part_longdescription) %]</td>
+  </tr>
 </table>
 
  <hr>
index f7033a6..65e23a3 100644 (file)
@@ -2,7 +2,7 @@
 [%- IF ok %]
 
  <p class="message_ok">[% LxERP.t8('The connection to the shop was established successfully.') %]</p>
- <p>[% LxERP.t8('Version: ')%][% HTML.escape(version) %]</p>
+ <p>[% LxERP.t8('Version')%]: [% HTML.escape(version) %]</p>
 
 [%- ELSE %]
 
index 0270326..2d364aa 100644 (file)
   <th align="right">[% LxERP.t8('Bank code') %]</th>
   <td>[%- L.input_tag("object.bank_code", SELF.object.bank_code, style=style) %]</td>
  </tr>
+ <tr>
+  <th align="right">[% LxERP.t8('Bank Account Id Number (Swiss)') %]</th>
+  <td>[%- L.input_tag("object.bank_account_id", SELF.object.bank_account_id, style=style) %]</td>
+ </tr>
  <tr>
   <th align="right">[% LxERP.t8('Chart') %]</th>
   <td>[% P.chart.picker('object.chart_id', SELF.object.chart_id, type='AR_paid,AP_paid', category='A,L,Q', choose=1, style=style, "data-validate"="required", "data-title"=LxERP.t8("Chart")) %]</td>
   <th align="right">[% LxERP.t8('Use for Factur-X/ZUGFeRD') %]</th>
   <td>[% L.checkbox_tag('object.use_for_zugferd', checked = SELF.object.use_for_zugferd, for_submit=1) %]</td>
  </tr>
+ <tr>
+  <th align="right">[% LxERP.t8('Use for Swiss QR-Bill') %]</th>
+  <td>[% L.checkbox_tag('object.use_for_qrbill', checked = SELF.object.use_for_qrbill, for_submit=1) %]</td>
+ </tr>
  <tr>
   <th align="right">[% LxERP.t8('Obsolete') %]</th>
   <td>[% L.checkbox_tag('object.obsolete', checked = SELF.object.obsolete, for_submit=1) %]</td>
index 0691f17..cf252b9 100644 (file)
@@ -25,4 +25,9 @@
   <th align="right">[% LxERP.t8("Long Dates") %]</th>
   <td>[% L.yes_no_tag("object.output_longdates", SELF.object.output_longdates, style=style) %]</td>
  </tr>
+ <tr>
+  <th align="right">[% LxERP.t8("Obsolete") %]</th>
+  <td>[% L.yes_no_tag("object.obsolete", SELF.object.obsolete, style=style) %]</td>
+ </tr>
+
 </table>
index fd4a905..ec7f817 100644 (file)
@@ -10,4 +10,9 @@
   <th align="right">[% LxERP.t8("Obsolete") %]</th>
   <td>[% L.checkbox_tag("object.obsolete", checked=SELF.object.obsolete, for_submit=1) %]</td>
  </tr>
+ <tr>
+  <th align="right">[% LxERP.t8("Delete for Customers") %]</th>
+  <td>[% L.checkbox_tag("SELF.remove_customer_pricegroup", checked=SELF.remove_customer_pricegroup, for_submit=1) %] [% LxERP.t8("This will also remove this pricegroup for all customers.") %]</td>
+ </tr>
+
 </table>
index def92cd..694e1fd 100644 (file)
           [% L.date_tag('todate') %]
         </td>
        </tr>
+       [% CUSTOM_VARIABLES_FILTER_CODE %]
       </table>
      </td>
     </tr>
         <td nowrap><label for="l_projectnumber">[% 'Project Number' | $T8 %]</label></td>
        </tr>
       </table>
+      <table>
+       [% CUSTOM_VARIABLES_INCLUSION_CODE %]
+      </table>
      </td>
     </tr>
    </table>
index c1dea3f..f0635c1 100644 (file)
         <th align="right" nowrap>[% 'Part Description' | $T8 %]:</th>
         <td><input name="description" size=40></td>
        </tr>
+       <tr>
+        <th align="right" nowrap>[% 'Partsgroup' | $T8 %]:</th>
+        <td>[% L.select_tag('partsgroup_id', PARTSGROUPS, value_key = 'id', title_key = 'partsgroup', with_empty = 1) %]</td>
+       </tr>
        <tr>
         <th align="right" nowrap>[% 'Charge Number' | $T8 %]:</th>
         <td><input name="chargenumber" size=40></td>
          [% L.input_number_tag("per_page", 20, size=4) %]
         </td>
        </tr>
+       [% CUSTOM_VARIABLES_FILTER_CODE %]
       </table>
      </td>
     </tr>
         <td align="right"><input name="l_list_price" id="l_list_price" class="checkbox" type="checkbox" value="Y"></td>
         <td nowrap><label for="l_list_price">[% 'List Price' | $T8 %]</label></td>
        </tr>
-       [% IF INCLUDABLE_CVAR_CONFIGS %]
-         <tr><td colspan="6"><hr noshade height="1"></td></tr>
-         [% FOREACH cvar_cfg = INCLUDABLE_CVAR_CONFIGS %]
-         <tr>
-          <td colspan="2" align="left">
-           [% name__ = cvar_cfg.name;
-            L.checkbox_tag("l_cvar_" _ name__, value="1", checked=(cvar_cfg.included_by_default ? 1 : ''), label=cvar_cfg.description) %]
-          </td>
-         </tr>
-         [% END %]
-       [% END %]
+      </table>
+      <table>
+       [% CUSTOM_VARIABLES_INCLUSION_CODE %]
       </table>
      </td>
     </tr>