From b11418d0e2c2691abcb5330e6b62bc1d45b741f1 Mon Sep 17 00:00:00 2001 From: Janusz Dobrowolski Date: Wed, 26 Jan 2011 12:53:35 +0000 Subject: [PATCH] Added closing transactions up to selected date. --- applications/generalledger.php | 3 +- config.default.php | 42 +++++++------ gl/includes/db/gl_db_trans.inc | 42 +++++++------ gl/inquiry/journal_inquiry.php | 33 +--------- gl/manage/close_period.php | 102 +++++++++++++++++++++++++++++++ includes/access_levels.inc | 5 ++ includes/db/audit_trail_db.inc | 98 +++++++++++++---------------- includes/ui/ui_input.inc | 21 +++++++ purchasing/po_entry_items.php | 4 +- themes/aqua/images/closed.png | Bin 0 -> 753 bytes themes/cool/images/closed.png | Bin 0 -> 753 bytes themes/default/images/closed.png | Bin 0 -> 753 bytes 12 files changed, 226 insertions(+), 124 deletions(-) create mode 100644 gl/manage/close_period.php create mode 100644 themes/aqua/images/closed.png create mode 100644 themes/cool/images/closed.png create mode 100644 themes/default/images/closed.png diff --git a/applications/generalledger.php b/applications/generalledger.php index c4c0522b..351e2486 100644 --- a/applications/generalledger.php +++ b/applications/generalledger.php @@ -71,7 +71,8 @@ class general_ledger_app extends application "gl/manage/gl_account_types.php?", 'SA_GLACCOUNTGROUP', MENU_MAINTENANCE); $this->add_rapp_function(2, _("GL Account &Classes"), "gl/manage/gl_account_classes.php?", 'SA_GLACCOUNTCLASS', MENU_MAINTENANCE); - $this->add_rapp_function(2, "",""); + $this->add_rapp_function(2, _("&Closing GL Transactions"), + "gl/manage/close_period.php?", 'SA_GLSETUP', MENU_MAINTENANCE); $this->add_rapp_function(2, _("&Revaluation of Currency Accounts"), "gl/manage/revaluate_currencies.php?", 'SA_EXCHANGERATE', MENU_MAINTENANCE); diff --git a/config.default.php b/config.default.php index 6705918f..55820f5a 100644 --- a/config.default.php +++ b/config.default.php @@ -120,7 +120,10 @@ if (!isset($path_to_root) || isset($_GET['path_to_root']) || isset($_POST['path_ /* suppress tax rates on documents. 0 = no, 1 = yes. */ $suppress_tax_rates = 0; - + + /* allow reopening closed transactions */ + $allow_gl_reopen = 0; + $dateformats = array("MMDDYYYY", "DDMMYYYY", "YYYYMMDD"); $dateseps = array("/", ".", "-", " "); $thoseps = array(",", ".", " "); @@ -204,25 +207,26 @@ if(isset($_SESSION["wa_current_user"])) { if (!defined('ICON_EDIT')) { - define("ICON_EDIT", "edit.gif"); - define("ICON_DELETE", "delete.gif"); - define("ICON_ADD", "ok.gif"); - define("ICON_UPDATE", "ok.gif"); - define("ICON_OK", "ok.gif"); - define("ICON_CANCEL", "cancel.png"); - define("ICON_GL", "gl.png"); - define("ICON_PRINT", "print.png"); - define("ICON_PDF", "pdf.gif"); - define("ICON_DOC", "invoice.gif"); - define("ICON_CREDIT", "credit.gif"); - define("ICON_RECEIVE", "receive.gif"); - define("ICON_DOWN", "download.gif"); - define("ICON_MONEY", "money.png"); - define("ICON_REMOVE", "remove.png"); - define("ICON_REPORT", "report.png"); - define("ICON_VIEW", "view.gif"); + define("ICON_EDIT", "edit.gif"); + define("ICON_DELETE", "delete.gif"); + define("ICON_ADD", "ok.gif"); + define("ICON_UPDATE", "ok.gif"); + define("ICON_OK", "ok.gif"); + define("ICON_CANCEL", "cancel.png"); + define("ICON_GL", "gl.png"); + define("ICON_PRINT", "print.png"); + define("ICON_PDF", "pdf.gif"); + define("ICON_DOC", "invoice.gif"); + define("ICON_CREDIT", "credit.gif"); + define("ICON_RECEIVE", "receive.gif"); + define("ICON_DOWN", "download.gif"); + define("ICON_MONEY", "money.png"); + define("ICON_REMOVE", "remove.png"); + define("ICON_REPORT", "report.png"); + define("ICON_VIEW", "view.gif"); define("ICON_SUBMIT", "ok.gif"); - define("ICON_ESCAPE", "escape.png"); + define("ICON_ESCAPE", "escape.png"); + define("ICON_CLOSED", "closed.png"); } ?> \ No newline at end of file diff --git a/gl/includes/db/gl_db_trans.inc b/gl/includes/db/gl_db_trans.inc index 7677fa3e..b9765713 100644 --- a/gl/includes/db/gl_db_trans.inc +++ b/gl/includes/db/gl_db_trans.inc @@ -92,7 +92,7 @@ function add_gl_balance($type, $trans_id, $date_, $amount, $person_type_id=null, $amount, null, $person_type_id, $person_id, "The balanced GL transaction could not be inserted"); else return 0; -} +} //-------------------------------------------------------------------------------- @@ -145,28 +145,31 @@ function get_gl_transactions($from_date, $to_date, $trans_no=0, function get_gl_trans($type, $trans_id) { $sql = "SELECT gl.*, cm.account_name, IF(ISNULL(refs.reference), '', refs.reference) AS reference FROM " - .TB_PREF."gl_trans as gl - LEFT JOIN ".TB_PREF."chart_master as cm ON gl.account = cm.account_code - LEFT JOIN ".TB_PREF."refs as refs ON (gl.type=refs.type AND gl.type_no=refs.id)" - ." WHERE gl.type= ".db_escape($type) - ." AND gl.type_no = ".db_escape($trans_id) - ." ORDER BY counter"; + .TB_PREF."gl_trans as gl" + . " LEFT JOIN ".TB_PREF."chart_master as cm ON gl.account = cm.account_code + LEFT JOIN ".TB_PREF."refs as refs ON (gl.type=refs.type AND gl.type_no=refs.id)"; + $sql .= " WHERE gl.type= ".db_escape($type) + ." AND gl.type_no = ".db_escape($trans_id); + $sql .= " ORDER BY counter"; return db_query($sql, "The gl transactions could not be retrieved"); } //-------------------------------------------------------------------------------- -function get_gl_wo_cost_trans($trans_id, $person_id=-1) +function get_gl_wo_cost_trans($trans_id, $cost_type=-1) { - $sql = "SELECT ".TB_PREF."gl_trans.*, ".TB_PREF."chart_master.account_name FROM " - .TB_PREF."gl_trans, ".TB_PREF."chart_master - WHERE ".TB_PREF."chart_master.account_code=".TB_PREF."gl_trans.account - AND ".TB_PREF."gl_trans.type=".ST_WORKORDER - ." AND ".TB_PREF."gl_trans.type_no=".db_escape($trans_id)." - AND ".TB_PREF."gl_trans.person_type_id=".PT_WORKORDER; - if ($person_id != -1) - $sql .= " AND ".TB_PREF."gl_trans.person_id=".db_escape($person_id); - $sql .= " AND amount < 0"; + $sql = "SELECT costing.*, gl.*, chart.account_name, com.memo_ FROM " + .TB_PREF."wo_costing costing, " + .TB_PREF."gl_trans gl LEFT JOIN ".TB_PREF."comments com ON gl.type=com.type AND gl.type_no=com.id," + .TB_PREF."chart_master chart + WHERE + costing.workorder_id=".db_escape($trans_id) + ." AND chart.account_code=gl.account + AND gl.type=costing.trans_type + AND gl.type_no=costing.trans_no"; + if ($cost_type != -1) + $sql .= " AND costing.cost_type=".db_escape($cost_type); + $sql .= " AND amount < 0"; return db_query($sql, "The gl transactions could not be retrieved"); } @@ -642,7 +645,10 @@ function get_sql_for_journal_inquiry($filter, $from, $to, $ref='', $memo='', $al if (!$alsoclosed) { $sql .= " AND gl_seq=0"; } - $sql .= " GROUP BY gl.type, gl.type_no"; + else + $sql .= " AND NOT ISNULL(a.gl_seq)"; + + $sql .= " GROUP BY tran_date, gl_seq, gl.type, gl.type_no"; return $sql; } ?> \ No newline at end of file diff --git a/gl/inquiry/journal_inquiry.php b/gl/inquiry/journal_inquiry.php index dccef78f..3fd59521 100644 --- a/gl/inquiry/journal_inquiry.php +++ b/gl/inquiry/journal_inquiry.php @@ -79,38 +79,9 @@ function gl_link($row) return get_gl_view_str($row["type"], $row["type_no"]); } -$editors = array( - ST_JOURNAL => "/gl/gl_journal.php?ModifyGL=Yes&trans_no=%d&trans_type=%d", - ST_BANKPAYMENT => "/gl/gl_bank.php?ModifyPayment=Yes&trans_no=%d&trans_type=%d", - ST_BANKDEPOSIT => "/gl/gl_bank.php?ModifyDeposit=Yes&trans_no=%d&trans_type=%d", -// 4=> Funds Transfer, - ST_SALESINVOICE => "/sales/customer_invoice.php?ModifyInvoice=%d", -// 11=> -// free hand (debtors_trans.order_==0) -// "/sales/credit_note_entry.php?ModifyCredit=%d" -// credit invoice -// "/sales/customer_credit_invoice.php?ModifyCredit=%d" -// 12=> Customer Payment, - ST_CUSTDELIVERY => "/sales/customer_delivery.php?ModifyDelivery=%d", -// 16=> Location Transfer, -// 17=> Inventory Adjustment, -// 20=> Supplier Invoice, -// 21=> Supplier Credit Note, -// 22=> Supplier Payment, -// 25=> Purchase Order Delivery, -// 28=> Work Order Issue, -// 29=> Work Order Production", -// 35=> Cost Update, -); - function edit_link($row) { - global $editors; - - return isset($editors[$row["type"]]) && !is_closed_trans($row["type"], $row["type_no"]) ? - pager_link(_("Edit"), - sprintf($editors[$row["type"]], $row["type_no"], $row["type"]), - ICON_EDIT) : ''; + return edit_trans_link($row["type"], $row["type_no"]); } $sql = get_sql_for_journal_inquiry(get_post('filterType', -1), get_post('FromDate'), @@ -118,7 +89,7 @@ $sql = get_sql_for_journal_inquiry(get_post('filterType', -1), get_post('FromDat $cols = array( _("#") => array('fun'=>'journal_pos', 'align'=>'center'), - _("Date") =>array('name'=>'tran_date','type'=>'date','ord'=>'desc'), + _("Date") =>array('name'=>'tran_date','type'=>'date', 'ord' => check_value('AlsoClosed') ? 'asc' : 'desc'), _("Type") => array('fun'=>'systype_name'), _("Trans #") => array('fun'=>'view_link'), _("Reference"), diff --git a/gl/manage/close_period.php b/gl/manage/close_period.php new file mode 100644 index 00000000..76fc317f --- /dev/null +++ b/gl/manage/close_period.php @@ -0,0 +1,102 @@ +. +***********************************************************************/ + +$page_security = 'SA_GLCLOSE'; +$path_to_root = "../.."; +include_once($path_to_root . "/includes/session.inc"); + +include_once($path_to_root . "/includes/date_functions.inc"); +include_once($path_to_root . "/includes/ui.inc"); +include_once($path_to_root . "/includes/banking.inc"); + +$js = ""; +if ($use_date_picker) + $js .= get_js_date_picker(); +page(_($help_context = "Closing GL Transactions"), false, false, "", $js); + +//--------------------------------------------------------------------------------------------- +function check_data() +{ + global $Refs, $allow_gl_reopen; + + if (!is_date($_POST['date']) || date1_greater_date2($_POST['date'], Today())) + { + display_error( _("The entered date is invalid.")); + set_focus('date'); + return false; + } + if (date1_greater_date2(sql2date(get_company_pref('gl_closing_date')), $_POST['date'])) + { + if (!$allow_gl_reopen) { + display_error(_("The entered date is earlier than date already selected as closing date.")); + set_focus('date'); + return false; + } elseif (!user_check_access('SA_GLREOPEN')) { + display_error(_("You are not allowed to reopen already closed transactions.")); + set_focus('date'); + return false; + } + } + return true; +} + +//--------------------------------------------------------------------------------------------- + +function handle_submit() +{ + if (!check_data()) + return; + + if (!close_transactions($_POST['date'])) + { + display_notification( + sprintf( _("All transactions resulting in GL accounts changes up to %s has been closed for further edition."), + sql2date(get_company_pref('gl_closing_date'))) ); + } + +} + + +//--------------------------------------------------------------------------------------------- + +function clear_data() +{ + unset($_POST['date_']); +} + +//--------------------------------------------------------------------------------------------- + +if (get_post('submit')) + handle_submit(); +else + display_note(_("Using this feature you can prevent entering new transactions
+ and disable edition of already entered transactions up to specified date.
+ Only transactions which can generate GL postings are subject to the constraint.")); + +//--------------------------------------------------------------------------------------------- + +br(1); +start_form(); +start_table(TABLESTYLE2); +if (!isset($_POST['date'])) { + $cdate = sql2date(get_company_pref('gl_closing_date')); + $_POST['date'] = $cdate ;// ? end_month(add_months($cdate, 1)) : Today(); +} +date_row(_("End date of closing period:"), 'date'); +end_table(1); + +submit_center('submit', _("Close Transactions"), true, false); +end_form(); + +end_page(); + +?> diff --git a/includes/access_levels.inc b/includes/access_levels.inc index 7ea510a6..afc364f3 100644 --- a/includes/access_levels.inc +++ b/includes/access_levels.inc @@ -227,6 +227,8 @@ $security_areas =array( 'SA_FISCALYEARS' => array(SS_GL_C|9, _("Fiscal years maintenance")), 'SA_GLSETUP' => array(SS_GL_C|10, _("Company GL setup")), 'SA_GLACCOUNTTAGS' => array(SS_GL_C|11, _("GL Account tags")), + 'SA_GLCLOSE' => array(SS_GL_C|14, _("Closing GL transactions")), + 'SA_GLREOPEN' => array(SS_GL_C|15, _("Reopening GL transactions")), // see below 'SA_MULTIFISCALYEARS' => array(SS_GL_C|13, _("Allow entry on non closed Fiscal years")), 'SA_BANKTRANSVIEW' => array(SS_GL|1, _("Bank transactions view")), @@ -247,6 +249,9 @@ $security_areas =array( 'SA_BANKREP' => array(SS_GL_A|3, _("Bank reports and inquiries")), 'SA_GLREP' => array(SS_GL_A|4, _("GL reports and inquiries")), ); + +if (!@$allow_gl_reopen) + unset($security_areas['SA_GLREOPEN']); /* This function should be called whenever we want to extend core access level system with new security areas and/or sections i.e.: diff --git a/includes/db/audit_trail_db.inc b/includes/db/audit_trail_db.inc index f9efe9a0..49abe1ca 100644 --- a/includes/db/audit_trail_db.inc +++ b/includes/db/audit_trail_db.inc @@ -12,21 +12,22 @@ function add_audit_trail($trans_type, $trans_no, $trans_date, $descr='') { + $date = date2sql($trans_date); $sql = "INSERT INTO ".TB_PREF."audit_trail" - . " (type, trans_no, user, fiscal_year, gl_date, description, gl_seq) + . " (type, trans_no, user, gl_date, description) VALUES(".db_escape($trans_type).", ".db_escape($trans_no)."," - . $_SESSION["wa_current_user"]->user. "," - . get_company_pref('f_year') ."," - . "'". date2sql($trans_date) ."'," - . db_escape($descr). ", 0)"; + . $_SESSION["wa_current_user"]->user . "," + . "'$date',". db_escape($descr). ")"; db_query($sql, "Cannot add audit info"); - // all audit records beside latest one should have gl_seq set to NULL + // all audit records beside just inserted one should have gl_seq set to NULL // to avoid need for subqueries (not existing in MySQL 3) all over the code - $sql = "UPDATE ".TB_PREF."audit_trail SET gl_seq = NULL" + $sql = "UPDATE ".TB_PREF."audit_trail audit LEFT JOIN ".TB_PREF."fiscal_year year ON year.begin<='$date' AND year.end>='$date' + SET audit.gl_seq = IF(audit.id=".db_insert_id().", 0, NULL)," + ."audit.fiscal_year=year.id" . " WHERE type=".db_escape($trans_type)." AND trans_no=" - .db_escape($trans_no)." AND id!=".db_insert_id(); + . db_escape($trans_no); db_query($sql, "Cannot update audit gl_seq"); } @@ -58,83 +59,72 @@ function get_audit_trail_last($trans_type, $trans_no) and reindex journal. */ function close_transactions($todate) { + + begin_transaction(); + $errors = 0; - $sql = "SELECT DISTINCT a.id, a.gl_date, a.fiscal_year" + // select only those audit trail records which produce any GL postings + $sql = "SELECT a.id, gl.tran_date, a.fiscal_year, a.gl_seq, + gl.tran_date <= '". date2sql($todate) ."' as closed" ." FROM ".TB_PREF."gl_trans gl" ." LEFT JOIN ". TB_PREF."audit_trail a ON (gl.type=a.type AND gl.type_no=a.trans_no)" - . " WHERE gl_date<='". date2sql($todate) ."'" - . " AND NOT ISNULL(gl_seq)" - . " ORDER BY a.fiscal_year, a.gl_date, a.id"; + . " WHERE NOT ISNULL(a.gl_seq) AND gl.amount!=0" // skip old audit records and voided transactions + . " GROUP BY a.id, gl.tran_date, a.fiscal_year, a.gl_seq ORDER BY a.fiscal_year, gl.tran_date, a.id"; $result = db_query($sql, "Cannot select transactions for closing"); if (db_num_rows($result)) { $last_year = 0; - while ($row = db_fetch($result)) { + if ($row['fiscal_year'] == null) { $errors = 1; continue; } + if ($last_year != $row['fiscal_year']) { $last_year = $row['fiscal_year']; - $counter = 1; // reset counter on fiscal year change - } else - $counter++; - $sql2 = "UPDATE ".TB_PREF."audit_trail SET" - . " gl_seq=$counter" - . " WHERE id=".$row['id']; - - db_query($sql2, "Cannot reindex journal"); + $counter = 0; // reset counter on fiscal year change + } + + $seq = $row['closed'] ? ++$counter : 0; + if ($row['gl_seq'] != $seq) { // update transaction status only when gl_seq has changed + $sql2 = "UPDATE ".TB_PREF."audit_trail SET" + . " gl_seq=$seq" + . " WHERE id=".$row['id']; + db_query($sql2, "Cannot reindex journal"); + } } } - if ($errors) display_warning(_("Some transactions journal GL postings were not indexed due to lack of audit trail record.")); -} - -/* - Reopen all transactions for edition up from date $fromdate -*/ -function open_transactions($fromdate) { - - $sql = "SELECT a.id, a.gl_date, a.fiscal_year" - ." FROM ".TB_PREF."gl_trans gl" - ." LEFT JOIN ". TB_PREF."audit_trail a ON - (gl.type=a.type AND gl.type_no=a.trans_no)" - . " WHERE gl_date>='". date2sql($fromdate) ."'" - . " AND !ISNULL(gl_seq)" - . " ORDER BY a.fiscal_year, a.gl_date, a.id"; - - $result = db_query($sql, "Cannot select transactions for openning"); - - if (db_num_rows($result)) { - $last_year = 0; + else + update_company_prefs(array('gl_closing_date'=> date2sql($todate))); + commit_transaction(); - while ($row = db_fetch($result)) { - if ($row['fiscal_year'] == null) { - continue; - } - $sql2 = "UPDATE ".TB_PREF."audit_trail SET" - . " gl_seq=0" - . " WHERE id=".$row['id']; - - db_query($sql2, "Cannot clear journal order"); - } - } + return $errors; } + /* Closed transactions have gl_seq number assigned. */ function is_closed_trans($type, $trans_no) { + + $cdate = get_company_pref('gl_closing_date'); + if (!$cdate) + return false; + +// FIXME: gl_date can be badly entered for some transactions due to bug in previous FA versions $sql = "SELECT gl_seq FROM ".TB_PREF."audit_trail" . " WHERE type=".db_escape($type) ." AND trans_no=".db_escape($trans_no) - ." AND gl_seq>0"; + ." AND gl_date<='$cdate'"; // date is stored in sql format +// ." AND (gl_date<='$cdate'" // some transaction can be not sequenced due to 0 amount, however after edition this could change +// ." OR gl_seq>0)"; $res = db_query($sql, "Cannot check transaction"); - return db_num_rows($res); + } ?> diff --git a/includes/ui/ui_input.inc b/includes/ui/ui_input.inc index 1889962d..ee84f0fd 100644 --- a/includes/ui/ui_input.inc +++ b/includes/ui/ui_input.inc @@ -931,4 +931,25 @@ function supplier_credit_row($supplier, $credit, $parms='') ."", $parms); } +/* + Edit transaction link to be used in transaction inquires +*/ +function edit_trans_link($trans_type, $trans_no, $url='') +{ + global $path_to_root, $trans_editors; + + if (!$url) $url = @$trans_editors[$trans_type]; + + if (!$trans_no || !$url) + return ''; + + if (is_closed_trans($trans_type, $trans_no)) { + return set_icon(ICON_CLOSED, _('Closed')); + } else { + $link_text = user_graphic_links() ? set_icon(ICON_EDIT, _('Edit')) : _('Edit'); + return "$link_text"; + } + +} + ?> \ No newline at end of file diff --git a/purchasing/po_entry_items.php b/purchasing/po_entry_items.php index d1713d03..a6ca4c33 100644 --- a/purchasing/po_entry_items.php +++ b/purchasing/po_entry_items.php @@ -57,6 +57,9 @@ if (isset($_GET['ModifyOrderNumber']) && is_numeric($_GET['ModifyOrderNumber'])) page($_SESSION['page_title'], false, false, "", $js); +if (isset($_GET['ModifyOrderNumber'])) + check_is_closed(ST_PURCHORDER, $_GET['ModifyOrderNumber']); + //--------------------------------------------------------------------------------------------------- check_db_has_suppliers(_("There are no suppliers defined in the system.")); @@ -412,7 +415,6 @@ function handle_commit_order() } $order_no = add_po($cart); new_doc_date($cart->orig_order_date); - $cart->order_no = $order_no; if ($cart->trans_type == ST_PURCHORDER) { unset($_SESSION['PO']); diff --git a/themes/aqua/images/closed.png b/themes/aqua/images/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..624c9edf8418fb4b472310d7463a9efb88dcd63a GIT binary patch literal 753 zcmVPx#32;bRa{vGf6951U69E94oEQKA00(qQO+^RW0Tv4r5R5X}r~m*0gGod|R5(wS zkV{BZaTvva|CxKIdGxUG(a>la)J#v5$`%ns)S^ub+Zco{qKHxk3k!mZ2-*ZaFe6$> zi=rTEQBY7|4+>KTQAkXRq;l*rGui0OIQQPU_iGVWQV5;ZS$yYw=N!d8{Jq_U8)HPX2p3zGVEsuDuGL5-l-I zGUY;x?4-}Az|;b;^*DSTW7crT1z?dj_5BrV{(+vv+1*PCR|GimI)RH%eD@lNKShbp zf@?RCz`GAKODI)He2PJ3%d^DMrZ6jubsltf^LEI`cy48ZKx+fi*jUTU zCAYcP`-Z!NUY^Wdh^`B61z2Evz_!7o01Ye~EP>x6uD!wPzB--`W_aZ)$H;=pf@wfL z4QDPx^C^%qFbq%`Fw@{_Z9p2Y8eo0HiX5h6)lrlMjs+y3kO8lNyA<5TAbGIHK&8ML zpG;tV17if;7(p$l#aU5@QeX>62GsI(n+2f%K{FqK)7y5C z_M4p8f|M0dj`Oo?VjRpo1cRU{&`n6Y|1emicQE1iaO;t|Slv47>yI65_f4?g;|2sA j0SX{q5CPkOyo>k`ItwJfXs=b400000NkvXXu0mjfT+l_% literal 0 HcmV?d00001 diff --git a/themes/cool/images/closed.png b/themes/cool/images/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..624c9edf8418fb4b472310d7463a9efb88dcd63a GIT binary patch literal 753 zcmVPx#32;bRa{vGf6951U69E94oEQKA00(qQO+^RW0Tv4r5R5X}r~m*0gGod|R5(wS zkV{BZaTvva|CxKIdGxUG(a>la)J#v5$`%ns)S^ub+Zco{qKHxk3k!mZ2-*ZaFe6$> zi=rTEQBY7|4+>KTQAkXRq;l*rGui0OIQQPU_iGVWQV5;ZS$yYw=N!d8{Jq_U8)HPX2p3zGVEsuDuGL5-l-I zGUY;x?4-}Az|;b;^*DSTW7crT1z?dj_5BrV{(+vv+1*PCR|GimI)RH%eD@lNKShbp zf@?RCz`GAKODI)He2PJ3%d^DMrZ6jubsltf^LEI`cy48ZKx+fi*jUTU zCAYcP`-Z!NUY^Wdh^`B61z2Evz_!7o01Ye~EP>x6uD!wPzB--`W_aZ)$H;=pf@wfL z4QDPx^C^%qFbq%`Fw@{_Z9p2Y8eo0HiX5h6)lrlMjs+y3kO8lNyA<5TAbGIHK&8ML zpG;tV17if;7(p$l#aU5@QeX>62GsI(n+2f%K{FqK)7y5C z_M4p8f|M0dj`Oo?VjRpo1cRU{&`n6Y|1emicQE1iaO;t|Slv47>yI65_f4?g;|2sA j0SX{q5CPkOyo>k`ItwJfXs=b400000NkvXXu0mjfT+l_% literal 0 HcmV?d00001 diff --git a/themes/default/images/closed.png b/themes/default/images/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..624c9edf8418fb4b472310d7463a9efb88dcd63a GIT binary patch literal 753 zcmVPx#32;bRa{vGf6951U69E94oEQKA00(qQO+^RW0Tv4r5R5X}r~m*0gGod|R5(wS zkV{BZaTvva|CxKIdGxUG(a>la)J#v5$`%ns)S^ub+Zco{qKHxk3k!mZ2-*ZaFe6$> zi=rTEQBY7|4+>KTQAkXRq;l*rGui0OIQQPU_iGVWQV5;ZS$yYw=N!d8{Jq_U8)HPX2p3zGVEsuDuGL5-l-I zGUY;x?4-}Az|;b;^*DSTW7crT1z?dj_5BrV{(+vv+1*PCR|GimI)RH%eD@lNKShbp zf@?RCz`GAKODI)He2PJ3%d^DMrZ6jubsltf^LEI`cy48ZKx+fi*jUTU zCAYcP`-Z!NUY^Wdh^`B61z2Evz_!7o01Ye~EP>x6uD!wPzB--`W_aZ)$H;=pf@wfL z4QDPx^C^%qFbq%`Fw@{_Z9p2Y8eo0HiX5h6)lrlMjs+y3kO8lNyA<5TAbGIHK&8ML zpG;tV17if;7(p$l#aU5@QeX>62GsI(n+2f%K{FqK)7y5C z_M4p8f|M0dj`Oo?VjRpo1cRU{&`n6Y|1emicQE1iaO;t|Slv47>yI65_f4?g;|2sA j0SX{q5CPkOyo>k`ItwJfXs=b400000NkvXXu0mjfT+l_% literal 0 HcmV?d00001 -- 2.30.2