Compare commits
10 Commits
7a6c70d3d8
...
cdacd1dc40
| Author | SHA1 | Date | |
|---|---|---|---|
| cdacd1dc40 | |||
| a371fe3bac | |||
| c2c206d585 | |||
| 6439eb79a1 | |||
| 77a65abdb5 | |||
| 09ce444fd0 | |||
| 88f2cd5ea7 | |||
| 28f282988d | |||
| 275652f7f7 | |||
| 442980a2f1 |
@@ -1,5 +1,9 @@
|
||||
.DS_Store
|
||||
|
||||
application/config/config.php
|
||||
application/config/database.php
|
||||
.htaccess
|
||||
|
||||
application/cache/*
|
||||
!application/cache/index.html
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /accounting_dev
|
||||
|
||||
# Redirect requests to index.php
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||
</IfModule>
|
||||
@@ -1,6 +0,0 @@
|
||||
<IfModule authz_core_module>
|
||||
Require all denied
|
||||
</IfModule>
|
||||
<IfModule !authz_core_module>
|
||||
Deny from all
|
||||
</IfModule>
|
||||
@@ -1,533 +0,0 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Base Site URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| URL to your CodeIgniter root. Typically this will be your base URL,
|
||||
| WITH a trailing slash:
|
||||
|
|
||||
| http://example.com/
|
||||
|
|
||||
| WARNING: You MUST set this value!
|
||||
|
|
||||
| If it is not set, then CodeIgniter will try to guess the protocol and
|
||||
| path to your installation, but due to security concerns the hostname will
|
||||
| be set to $_SERVER['SERVER_ADDR'] if available, or localhost otherwise.
|
||||
| The auto-detection mechanism exists only for convenience during
|
||||
| development and MUST NOT be used in production!
|
||||
|
|
||||
| If you need to allow multiple domains, remember that this file is still
|
||||
| a PHP script and you can easily do that on your own.
|
||||
|
|
||||
*/
|
||||
$config['base_url'] = 'http://localhost/accounting_dev/';
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Index File
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Typically this will be your index.php file, unless you've renamed it to
|
||||
| something else. If you are using mod_rewrite to remove the page set this
|
||||
| variable so that it is blank.
|
||||
|
|
||||
*/
|
||||
$config['index_page'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| URI PROTOCOL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This item determines which server global should be used to retrieve the
|
||||
| URI string. The default setting of 'REQUEST_URI' works for most servers.
|
||||
| If your links do not seem to work, try one of the other delicious flavors:
|
||||
|
|
||||
| 'REQUEST_URI' Uses $_SERVER['REQUEST_URI']
|
||||
| 'QUERY_STRING' Uses $_SERVER['QUERY_STRING']
|
||||
| 'PATH_INFO' Uses $_SERVER['PATH_INFO']
|
||||
|
|
||||
| WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
|
||||
*/
|
||||
$config['uri_protocol'] = 'REQUEST_URI';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| URL suffix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to add a suffix to all URLs generated by CodeIgniter.
|
||||
| For more information please see the user guide:
|
||||
|
|
||||
| https://codeigniter.com/userguide3/general/urls.html
|
||||
|
|
||||
| Note: This option is ignored for CLI requests.
|
||||
*/
|
||||
$config['url_suffix'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Language
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This determines which set of language files should be used. Make sure
|
||||
| there is an available translation if you intend to use something other
|
||||
| than english.
|
||||
|
|
||||
*/
|
||||
$config['language'] = 'english';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Character Set
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This determines which character set is used by default in various methods
|
||||
| that require a character set to be provided.
|
||||
|
|
||||
| See http://php.net/htmlspecialchars for a list of supported charsets.
|
||||
|
|
||||
*/
|
||||
$config['charset'] = 'UTF-8';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enable/Disable System Hooks
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you would like to use the 'hooks' feature you must enable it by
|
||||
| setting this variable to TRUE (boolean). See the user guide for details.
|
||||
|
|
||||
*/
|
||||
$config['enable_hooks'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Class Extension Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This item allows you to set the filename/classname prefix when extending
|
||||
| native libraries. For more information please see the user guide:
|
||||
|
|
||||
| https://codeigniter.com/userguide3/general/core_classes.html
|
||||
| https://codeigniter.com/userguide3/general/creating_libraries.html
|
||||
|
|
||||
*/
|
||||
$config['subclass_prefix'] = 'MY_';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Composer auto-loading
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enabling this setting will tell CodeIgniter to look for a Composer
|
||||
| package auto-loader script in application/vendor/autoload.php.
|
||||
|
|
||||
| $config['composer_autoload'] = TRUE;
|
||||
|
|
||||
| Or if you have your vendor/ directory located somewhere else, you
|
||||
| can opt to set a specific path as well:
|
||||
|
|
||||
| $config['composer_autoload'] = '/path/to/vendor/autoload.php';
|
||||
|
|
||||
| For more information about Composer, please visit http://getcomposer.org/
|
||||
|
|
||||
| Note: This will NOT disable or override the CodeIgniter-specific
|
||||
| autoloading (application/config/autoload.php)
|
||||
*/
|
||||
$config['composer_autoload'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Allowed URL Characters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This lets you specify which characters are permitted within your URLs.
|
||||
| When someone tries to submit a URL with disallowed characters they will
|
||||
| get a warning message.
|
||||
|
|
||||
| As a security measure you are STRONGLY encouraged to restrict URLs to
|
||||
| as few characters as possible. By default only these are allowed: a-z 0-9~%.:_-
|
||||
|
|
||||
| Leave blank to allow all characters -- but only if you are insane.
|
||||
|
|
||||
| The configured value is actually a regular expression character group
|
||||
| and it will be executed as: ! preg_match('/^[<permitted_uri_chars>]+$/i
|
||||
|
|
||||
| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
|
||||
|
|
||||
*/
|
||||
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enable Query Strings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default CodeIgniter uses search-engine friendly segment based URLs:
|
||||
| example.com/who/what/where/
|
||||
|
|
||||
| You can optionally enable standard query string based URLs:
|
||||
| example.com?who=me&what=something&where=here
|
||||
|
|
||||
| Options are: TRUE or FALSE (boolean)
|
||||
|
|
||||
| The other items let you set the query string 'words' that will
|
||||
| invoke your controllers and its functions:
|
||||
| example.com/index.php?c=controller&m=function
|
||||
|
|
||||
| Please note that some of the helpers won't work as expected when
|
||||
| this feature is enabled, since CodeIgniter is designed primarily to
|
||||
| use segment based URLs.
|
||||
|
|
||||
*/
|
||||
$config['enable_query_strings'] = FALSE;
|
||||
$config['controller_trigger'] = 'c';
|
||||
$config['function_trigger'] = 'm';
|
||||
$config['directory_trigger'] = 'd';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Allow $_GET array
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default CodeIgniter enables access to the $_GET array. If for some
|
||||
| reason you would like to disable it, set 'allow_get_array' to FALSE.
|
||||
|
|
||||
| WARNING: This feature is DEPRECATED and currently available only
|
||||
| for backwards compatibility purposes!
|
||||
|
|
||||
*/
|
||||
$config['allow_get_array'] = TRUE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Error Logging Threshold
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You can enable error logging by setting a threshold over zero. The
|
||||
| threshold determines what gets logged. Threshold options are:
|
||||
|
|
||||
| 0 = Disables logging, Error logging TURNED OFF
|
||||
| 1 = Error Messages (including PHP errors)
|
||||
| 2 = Debug Messages
|
||||
| 3 = Informational Messages
|
||||
| 4 = All Messages
|
||||
|
|
||||
| You can also pass an array with threshold levels to show individual error types
|
||||
|
|
||||
| array(2) = Debug Messages, without Error Messages
|
||||
|
|
||||
| For a live site you'll usually only enable Errors (1) to be logged otherwise
|
||||
| your log files will fill up very fast.
|
||||
|
|
||||
*/
|
||||
$config['log_threshold'] = 4;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Error Logging Directory Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Leave this BLANK unless you would like to set something other than the default
|
||||
| application/logs/ directory. Use a full server path with trailing slash.
|
||||
|
|
||||
*/
|
||||
$config['log_path'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log File Extension
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default filename extension for log files. The default 'php' allows for
|
||||
| protecting the log files via basic scripting, when they are to be stored
|
||||
| under a publicly accessible directory.
|
||||
|
|
||||
| Note: Leaving it blank will default to 'php'.
|
||||
|
|
||||
*/
|
||||
$config['log_file_extension'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log File Permissions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The file system permissions to be applied on newly created log files.
|
||||
|
|
||||
| IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal
|
||||
| integer notation (i.e. 0700, 0644, etc.)
|
||||
*/
|
||||
$config['log_file_permissions'] = 0644;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Date Format for Logs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Each item that is logged has an associated date. You can use PHP date
|
||||
| codes to set your own date formatting
|
||||
|
|
||||
*/
|
||||
$config['log_date_format'] = 'Y-m-d H:i:s';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Error Views Directory Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Leave this BLANK unless you would like to set something other than the default
|
||||
| application/views/errors/ directory. Use a full server path with trailing slash.
|
||||
|
|
||||
*/
|
||||
$config['error_views_path'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Directory Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Leave this BLANK unless you would like to set something other than the default
|
||||
| application/cache/ directory. Use a full server path with trailing slash.
|
||||
|
|
||||
*/
|
||||
$config['cache_path'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Include Query String
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Whether to take the URL query string into consideration when generating
|
||||
| output cache files. Valid options are:
|
||||
|
|
||||
| FALSE = Disabled
|
||||
| TRUE = Enabled, take all query parameters into account.
|
||||
| Please be aware that this may result in numerous cache
|
||||
| files generated for the same page over and over again.
|
||||
| array('q') = Enabled, but only take into account the specified list
|
||||
| of query parameters.
|
||||
|
|
||||
*/
|
||||
$config['cache_query_string'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you use the Encryption class, you must set an encryption key.
|
||||
| See the user guide for more info.
|
||||
|
|
||||
| https://codeigniter.com/userguide3/libraries/encryption.html
|
||||
|
|
||||
*/
|
||||
$config['encryption_key'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 'sess_driver'
|
||||
|
|
||||
| The storage driver to use: files, database, redis, memcached
|
||||
|
|
||||
| 'sess_cookie_name'
|
||||
|
|
||||
| The session cookie name, must contain only [0-9a-z_-] characters
|
||||
|
|
||||
| 'sess_samesite'
|
||||
|
|
||||
| Session cookie SameSite attribute: Lax (default), Strict or None
|
||||
|
|
||||
| 'sess_expiration'
|
||||
|
|
||||
| The number of SECONDS you want the session to last.
|
||||
| Setting to 0 (zero) means expire when the browser is closed.
|
||||
|
|
||||
| 'sess_save_path'
|
||||
|
|
||||
| The location to save sessions to, driver dependent.
|
||||
|
|
||||
| For the 'files' driver, it's a path to a writable directory.
|
||||
| WARNING: Only absolute paths are supported!
|
||||
|
|
||||
| For the 'database' driver, it's a table name.
|
||||
| Please read up the manual for the format with other session drivers.
|
||||
|
|
||||
| IMPORTANT: You are REQUIRED to set a valid save path!
|
||||
|
|
||||
| 'sess_match_ip'
|
||||
|
|
||||
| Whether to match the user's IP address when reading the session data.
|
||||
|
|
||||
| WARNING: If you're using the database driver, don't forget to update
|
||||
| your session table's PRIMARY KEY when changing this setting.
|
||||
|
|
||||
| 'sess_time_to_update'
|
||||
|
|
||||
| How many seconds between CI regenerating the session ID.
|
||||
|
|
||||
| 'sess_regenerate_destroy'
|
||||
|
|
||||
| Whether to destroy session data associated with the old session ID
|
||||
| when auto-regenerating the session ID. When set to FALSE, the data
|
||||
| will be later deleted by the garbage collector.
|
||||
|
|
||||
| Other session cookie settings are shared with the rest of the application,
|
||||
| except for 'cookie_prefix' and 'cookie_httponly', which are ignored here.
|
||||
|
|
||||
*/
|
||||
$config['sess_driver'] = 'files';
|
||||
$config['sess_cookie_name'] = 'ci_session';
|
||||
$config['sess_samesite'] = 'Lax';
|
||||
$config['sess_expiration'] = 7200;
|
||||
$config['sess_save_path'] = sys_get_temp_dir();
|
||||
$config['sess_match_ip'] = FALSE;
|
||||
$config['sess_time_to_update'] = 300;
|
||||
$config['sess_regenerate_destroy'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cookie Related Variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 'cookie_prefix' = Set a cookie name prefix if you need to avoid collisions
|
||||
| 'cookie_domain' = Set to .your-domain.com for site-wide cookies
|
||||
| 'cookie_path' = Typically will be a forward slash
|
||||
| 'cookie_secure' = Cookie will only be set if a secure HTTPS connection exists.
|
||||
| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript)
|
||||
| 'cookie_samesite' = Cookie's samesite attribute (Lax, Strict or None)
|
||||
|
|
||||
| Note: These settings (with the exception of 'cookie_prefix' and
|
||||
| 'cookie_httponly') will also affect sessions.
|
||||
|
|
||||
*/
|
||||
$config['cookie_prefix'] = '';
|
||||
$config['cookie_domain'] = '';
|
||||
$config['cookie_path'] = '/';
|
||||
$config['cookie_secure'] = FALSE;
|
||||
$config['cookie_httponly'] = FALSE;
|
||||
$config['cookie_samesite'] = 'Lax';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Standardize newlines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Determines whether to standardize newline characters in input data,
|
||||
| meaning to replace \r\n, \r, \n occurrences with the PHP_EOL value.
|
||||
|
|
||||
| WARNING: This feature is DEPRECATED and currently available only
|
||||
| for backwards compatibility purposes!
|
||||
|
|
||||
*/
|
||||
$config['standardize_newlines'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global XSS Filtering
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Determines whether the XSS filter is always active when GET, POST or
|
||||
| COOKIE data is encountered
|
||||
|
|
||||
| WARNING: This feature is DEPRECATED and currently available only
|
||||
| for backwards compatibility purposes!
|
||||
|
|
||||
*/
|
||||
$config['global_xss_filtering'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cross Site Request Forgery
|
||||
|--------------------------------------------------------------------------
|
||||
| Enables a CSRF cookie token to be set. When set to TRUE, token will be
|
||||
| checked on a submitted form. If you are accepting user data, it is strongly
|
||||
| recommended CSRF protection be enabled.
|
||||
|
|
||||
| 'csrf_token_name' = The token name
|
||||
| 'csrf_cookie_name' = The cookie name
|
||||
| 'csrf_expire' = The number in seconds the token should expire.
|
||||
| 'csrf_regenerate' = Regenerate token on every submission
|
||||
| 'csrf_exclude_uris' = Array of URIs which ignore CSRF checks
|
||||
*/
|
||||
$config['csrf_protection'] = FALSE;
|
||||
$config['csrf_token_name'] = 'csrf_test_name';
|
||||
$config['csrf_cookie_name'] = 'csrf_cookie_name';
|
||||
$config['csrf_expire'] = 7200;
|
||||
$config['csrf_regenerate'] = TRUE;
|
||||
$config['csrf_exclude_uris'] = array();
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Output Compression
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enables Gzip output compression for faster page loads. When enabled,
|
||||
| the output class will test whether your server supports Gzip.
|
||||
| Even if it does, however, not all browsers support compression
|
||||
| so enable only if you are reasonably sure your visitors can handle it.
|
||||
|
|
||||
| Only used if zlib.output_compression is turned off in your php.ini.
|
||||
| Please do not use it together with httpd-level output compression.
|
||||
|
|
||||
| VERY IMPORTANT: If you are getting a blank page when compression is enabled it
|
||||
| means you are prematurely outputting something to your browser. It could
|
||||
| even be a line of whitespace at the end of one of your scripts. For
|
||||
| compression to work, nothing can be sent before the output buffer is called
|
||||
| by the output class. Do not 'echo' any values with compression enabled.
|
||||
|
|
||||
*/
|
||||
$config['compress_output'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Master Time Reference
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Options are 'local' or any PHP supported timezone. This preference tells
|
||||
| the system whether to use your server's local time as the master 'now'
|
||||
| reference, or convert it to the configured one timezone. See the 'date
|
||||
| helper' page of the user guide for information regarding date handling.
|
||||
|
|
||||
*/
|
||||
$config['time_reference'] = 'local';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Rewrite PHP Short Tags
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If your PHP installation does not have short tag support enabled CI
|
||||
| can rewrite the tags on-the-fly, enabling you to utilize that syntax
|
||||
| in your view files. Options are TRUE or FALSE (boolean)
|
||||
|
|
||||
| Note: You need to have eval() enabled for this to work.
|
||||
|
|
||||
*/
|
||||
$config['rewrite_short_tags'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Reverse Proxy IPs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If your server is behind a reverse proxy, you must whitelist the proxy
|
||||
| IP addresses from which CodeIgniter should trust headers such as
|
||||
| HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify
|
||||
| the visitor's IP address.
|
||||
|
|
||||
| You can use both an array or a comma-separated list of proxy addresses,
|
||||
| as well as specifying whole subnets. Here are a few examples:
|
||||
|
|
||||
| Comma-separated: '10.0.1.200,192.168.5.0/24'
|
||||
| Array: array('10.0.1.200', '192.168.5.0/24')
|
||||
*/
|
||||
$config['proxy_ips'] = '';
|
||||
@@ -1,98 +0,0 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| DATABASE CONNECTIVITY SETTINGS
|
||||
| -------------------------------------------------------------------
|
||||
| This file will contain the settings needed to access your database.
|
||||
|
|
||||
| For complete instructions please consult the 'Database Connection'
|
||||
| page of the User Guide.
|
||||
|
|
||||
| -------------------------------------------------------------------
|
||||
| EXPLANATION OF VARIABLES
|
||||
| -------------------------------------------------------------------
|
||||
|
|
||||
| ['dsn'] The full DSN string describe a connection to the database.
|
||||
| ['hostname'] The hostname of your database server.
|
||||
| ['username'] The username used to connect to the database
|
||||
| ['password'] The password used to connect to the database
|
||||
| ['database'] The name of the database you want to connect to
|
||||
| ['dbdriver'] The database driver. e.g.: mysqli.
|
||||
| Currently supported:
|
||||
| cubrid, ibase, mssql, mysql, mysqli, oci8,
|
||||
| odbc, pdo, postgre, sqlite, sqlite3, sqlsrv
|
||||
| ['dbprefix'] You can add an optional prefix, which will be added
|
||||
| to the table name when using the Query Builder class
|
||||
| ['pconnect'] TRUE/FALSE - Whether to use a persistent connection
|
||||
| ['db_debug'] TRUE/FALSE - Whether database errors should be displayed.
|
||||
| ['cache_on'] TRUE/FALSE - Enables/disables query caching
|
||||
| ['cachedir'] The path to the folder where cache files should be stored
|
||||
| ['char_set'] The character set used in communicating with the database
|
||||
| ['dbcollat'] The character collation used in communicating with the database
|
||||
| NOTE: For MySQL and MySQLi databases, this setting is only used
|
||||
| as a backup if your server is running PHP < 5.2.3 or MySQL < 5.0.7
|
||||
| (and in table creation queries made with DB Forge).
|
||||
| There is an incompatibility in PHP with mysql_real_escape_string() which
|
||||
| can make your site vulnerable to SQL injection if you are using a
|
||||
| multi-byte character set and are running versions lower than these.
|
||||
| Sites using Latin-1 or UTF-8 database character set and collation are unaffected.
|
||||
| ['swap_pre'] A default table prefix that should be swapped with the dbprefix
|
||||
| ['encrypt'] Whether or not to use an encrypted connection.
|
||||
|
|
||||
| 'mysql' (deprecated), 'sqlsrv' and 'pdo/sqlsrv' drivers accept TRUE/FALSE
|
||||
| 'mysqli' and 'pdo/mysql' drivers accept an array with the following options:
|
||||
|
|
||||
| 'ssl_key' - Path to the private key file
|
||||
| 'ssl_cert' - Path to the public key certificate file
|
||||
| 'ssl_ca' - Path to the certificate authority file
|
||||
| 'ssl_capath' - Path to a directory containing trusted CA certificates in PEM format
|
||||
| 'ssl_cipher' - List of *allowed* ciphers to be used for the encryption, separated by colons (':')
|
||||
| 'ssl_verify' - TRUE/FALSE; Whether verify the server certificate or not
|
||||
|
|
||||
| ['compress'] Whether or not to use client compression (MySQL only)
|
||||
| ['stricton'] TRUE/FALSE - forces 'Strict Mode' connections
|
||||
| - good for ensuring strict SQL while developing
|
||||
| ['ssl_options'] Used to set various SSL options that can be used when making SSL connections.
|
||||
| ['failover'] array - A array with 0 or more data for connections if the main should fail.
|
||||
| ['save_queries'] TRUE/FALSE - Whether to "save" all executed queries.
|
||||
| NOTE: Disabling this will also effectively disable both
|
||||
| $this->db->last_query() and profiling of DB queries.
|
||||
| When you run a query, with this setting set to TRUE (default),
|
||||
| CodeIgniter will store the SQL statement for debugging purposes.
|
||||
| However, this may cause high memory usage, especially if you run
|
||||
| a lot of SQL queries ... disable this to avoid that problem.
|
||||
|
|
||||
| The $active_group variable lets you choose which connection group to
|
||||
| make active. By default there is only one group (the 'default' group).
|
||||
|
|
||||
| The $query_builder variables lets you determine whether or not to load
|
||||
| the query builder class.
|
||||
*/
|
||||
$active_group = 'default';
|
||||
$query_builder = TRUE;
|
||||
|
||||
$db['default'] = array(
|
||||
'dsn' => '',
|
||||
'hostname' => '103.242.106.56', // tanpa port
|
||||
'port' => 3310, // port PostgreSQL
|
||||
'username' => 'accointing_dev',
|
||||
'password' => 'accointing_dev',
|
||||
'database' => 'accointing_dev',
|
||||
'dbdriver' => 'mysqli', // WAJIB: driver PostgreSQL
|
||||
'dbprefix' => '',
|
||||
'pconnect' => FALSE,
|
||||
'db_debug' => (ENVIRONMENT !== 'production'),
|
||||
'cache_on' => FALSE,
|
||||
'cachedir' => '',
|
||||
'char_set' => 'utf8',
|
||||
'dbcollat' => 'utf8_general_ci', // PostgreSQL abaikan ini, tapi biarkan saja
|
||||
'swap_pre' => '',
|
||||
'encrypt' => FALSE,
|
||||
'compress' => FALSE,
|
||||
'stricton' => FALSE,
|
||||
'failover' => array(),
|
||||
'save_queries' => TRUE
|
||||
);
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Attendancemonthly extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->database();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
"active_menu" => "attendance_monthly"
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('employees/attendance_monthly');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
public function get_data()
|
||||
{
|
||||
$date = $this->input->get('date') . '-01';
|
||||
|
||||
if(!$date){
|
||||
$date = date('Y-m-d');
|
||||
}
|
||||
|
||||
$data = $this->db->query("
|
||||
SELECT
|
||||
a.*,
|
||||
e.employee_code,
|
||||
e.full_name
|
||||
FROM k_attendance_monthly a
|
||||
LEFT JOIN k_employees e ON e.id = a.employee_id
|
||||
WHERE a.month = '$date'
|
||||
ORDER BY a.updated_at DESC
|
||||
")->result();
|
||||
|
||||
$rows = [];
|
||||
$no = 1;
|
||||
|
||||
foreach($data as $row){
|
||||
|
||||
$rows[] = [
|
||||
$no++,
|
||||
$row->employee_code,
|
||||
$row->full_name,
|
||||
tanggal_indo($row->month,'F Y'),
|
||||
$row->status,
|
||||
'
|
||||
<button class="btn btn-sm btn-info btn-detail"
|
||||
data-id="'.$row->id.'" data-month="'.$row->month.'">Detail</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'data' => $rows
|
||||
]);
|
||||
}
|
||||
|
||||
// public function detail($id)
|
||||
// {
|
||||
// echo json_encode(
|
||||
// $this->db->get_where('k_attendance_monthly',['id'=>$id])->row()
|
||||
// );
|
||||
// }
|
||||
|
||||
public function detail($id, $month)
|
||||
{
|
||||
$header = $this->db
|
||||
->select('a.*, e.full_name, e.employee_code')
|
||||
->from('k_attendance_monthly a')
|
||||
->join('k_employees e','e.id = a.employee_id', 'left')
|
||||
->where('a.id',$id)
|
||||
->where('a.month',$month)
|
||||
->get()
|
||||
->row();
|
||||
|
||||
$startDate = $month;
|
||||
$endDate = substr($month, 0, 7) . date('-t');
|
||||
|
||||
$detail = $this->db
|
||||
->select('a.attendance_date, a.attendance_status, b.shift_name')
|
||||
->from('k_attendances a')
|
||||
->join('k_shifts b', 'b.id = a.shift_id', 'left')
|
||||
->where('a.employee_id', $header->employee_id)
|
||||
->where('a.attendance_date >=', $startDate)
|
||||
->where('a.attendance_date <=', $endDate)
|
||||
->get()
|
||||
->result();
|
||||
|
||||
echo json_encode([
|
||||
'header'=>$header,
|
||||
'detail'=>$detail
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -137,4 +137,220 @@ class Cronjob extends CI_Controller {
|
||||
'period' => $period
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// CRONJOB UNTUK LIHAT KEHADIRAN SELAMA 1 BULAN
|
||||
// =====================================================
|
||||
|
||||
// | Kriteria | Pengurangan |
|
||||
// | ---------------------- | ------------------: |
|
||||
// | Alpha | -20 poin / hari |
|
||||
// | Terlambat | -2 poin / kejadian |
|
||||
// | Izin (permit) | -1 poin / hari |
|
||||
// | Akumulasi telat | -1 poin / 60 menit |
|
||||
// | Akumulasi pulang cepat | -1 poin / 120 menit |
|
||||
|
||||
public function generateMonthlyAttendance()
|
||||
{
|
||||
$month = date('Y-m-01');
|
||||
|
||||
$startDate = date('Y-m-01', strtotime($month));
|
||||
$endDate = date('Y-m-t', strtotime($month));
|
||||
|
||||
$employees = $this->db
|
||||
->where('is_active', 1)
|
||||
->get('k_employees')
|
||||
->result();
|
||||
|
||||
$processed = 0;
|
||||
|
||||
$this->db->trans_begin();
|
||||
|
||||
try {
|
||||
|
||||
foreach ($employees as $employee) {
|
||||
|
||||
// Total Hari Kerja
|
||||
$schedule = $this->db->query("
|
||||
SELECT
|
||||
COUNT(*) AS total_hari_kerja
|
||||
FROM k_employee_shift_schedules
|
||||
WHERE employee_id = ?
|
||||
AND status IN ('published','done')
|
||||
AND schedule_date BETWEEN ? AND ?
|
||||
", array(
|
||||
$employee->id,
|
||||
$startDate,
|
||||
$endDate
|
||||
))->row();
|
||||
|
||||
$total_hari_kerja = (int) $schedule->total_hari_kerja;
|
||||
|
||||
// Rekap Absensi
|
||||
$attendance = $this->db->query("
|
||||
SELECT
|
||||
|
||||
COALESCE(SUM(attendance_status='present'),0) AS total_present,
|
||||
COALESCE(SUM(attendance_status='late'),0) AS total_late,
|
||||
COALESCE(SUM(attendance_status='alpha'),0) AS total_alpha,
|
||||
COALESCE(SUM(attendance_status='sick'),0) AS total_sick,
|
||||
COALESCE(SUM(attendance_status='permit'),0) AS total_permit,
|
||||
COALESCE(SUM(attendance_status='annual'),0) AS total_annual,
|
||||
|
||||
COALESCE(SUM(late_minutes),0) AS total_late_minutes,
|
||||
COALESCE(SUM(early_leave_minutes),0) AS total_early_leave_minutes,
|
||||
|
||||
COALESCE(SUM(work_hours),0) AS total_work_hours,
|
||||
COALESCE(SUM(overtime_hours),0) AS total_overtime_hours
|
||||
|
||||
FROM k_attendances
|
||||
WHERE employee_id = ?
|
||||
AND attendance_date BETWEEN ? AND ?
|
||||
", array(
|
||||
$employee->id,
|
||||
$startDate,
|
||||
$endDate
|
||||
))->row();
|
||||
|
||||
$total_present = (int) $attendance->total_present;
|
||||
$total_late = (int) $attendance->total_late;
|
||||
$total_alpha = (int) $attendance->total_alpha;
|
||||
$total_sick = (int) $attendance->total_sick;
|
||||
$total_permit = (int) $attendance->total_permit;
|
||||
$total_annual = (int) $attendance->total_annual;
|
||||
|
||||
// Kehadiran
|
||||
$total_hadir = $total_present + $total_late;
|
||||
|
||||
$attendance_percentage = 0;
|
||||
|
||||
if ($total_hari_kerja > 0) {
|
||||
$attendance_percentage = round(
|
||||
($total_hadir / $total_hari_kerja) * 100,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
// SCOR
|
||||
$score = 100;
|
||||
|
||||
// Alpha
|
||||
$score -= ($total_alpha * 20);
|
||||
|
||||
// Telat
|
||||
$score -= ($total_late * 2);
|
||||
|
||||
// Izin
|
||||
$score -= ($total_permit * 1);
|
||||
|
||||
// Total menit telat
|
||||
$score -= floor(
|
||||
((int) $attendance->total_late_minutes) / 60
|
||||
);
|
||||
|
||||
// Total menit pulang cepat
|
||||
$score -= floor(
|
||||
((int) $attendance->total_early_leave_minutes) / 120
|
||||
);
|
||||
|
||||
if ($score < 0) {
|
||||
$score = 0;
|
||||
}
|
||||
|
||||
// LOGIKA STATUS
|
||||
if ($score >= 90) {
|
||||
$status = 'baik sekali';
|
||||
} elseif ($score >= 75) {
|
||||
$status = 'baik';
|
||||
} elseif ($score >= 60) {
|
||||
$status = 'kurang baik';
|
||||
} else {
|
||||
$status = 'buruk';
|
||||
}
|
||||
|
||||
// INSERT OR UPDATE TO k_attendance_monthly
|
||||
$sql = "
|
||||
INSERT INTO k_attendance_monthly (
|
||||
employee_id, month,
|
||||
total_present, total_late, total_alpha, total_sick, total_permit, total_annual,
|
||||
total_late_minutes, total_early_leave_minutes,
|
||||
total_work_hours, total_overtime_hours,
|
||||
total_hari_kerja, total_hadir, attendance_percentage,
|
||||
score, status
|
||||
)
|
||||
VALUES (
|
||||
?, ?,
|
||||
?, ?, ?, ?, ?, ?,
|
||||
?, ?,
|
||||
?, ?,
|
||||
?, ?, ?,
|
||||
?, ?
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
total_present = VALUES(total_present),
|
||||
total_late = VALUES(total_late),
|
||||
total_alpha = VALUES(total_alpha),
|
||||
total_sick = VALUES(total_sick),
|
||||
total_permit = VALUES(total_permit),
|
||||
total_annual = VALUES(total_annual),
|
||||
total_late_minutes = VALUES(total_late_minutes),
|
||||
total_early_leave_minutes = VALUES(total_early_leave_minutes),
|
||||
total_work_hours = VALUES(total_work_hours),
|
||||
total_overtime_hours = VALUES(total_overtime_hours),
|
||||
total_hari_kerja = VALUES(total_hari_kerja),
|
||||
total_hadir = VALUES(total_hadir),
|
||||
attendance_percentage = VALUES(attendance_percentage),
|
||||
score = VALUES(score),
|
||||
status = VALUES(status),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
";
|
||||
|
||||
$this->db->query($sql, array(
|
||||
$employee->id,
|
||||
$month,
|
||||
$total_present,
|
||||
$total_late,
|
||||
$total_alpha,
|
||||
$total_sick,
|
||||
$total_permit,
|
||||
$total_annual,
|
||||
(int)$attendance->total_late_minutes,
|
||||
(int)$attendance->total_early_leave_minutes,
|
||||
(float)$attendance->total_work_hours,
|
||||
(float)$attendance->total_overtime_hours,
|
||||
$total_hari_kerja,
|
||||
$total_hadir,
|
||||
$attendance_percentage,
|
||||
$score,
|
||||
$status
|
||||
));
|
||||
|
||||
$processed++;
|
||||
}
|
||||
|
||||
if ($this->db->trans_status() === FALSE) {
|
||||
throw new Exception('Transaction failed');
|
||||
}
|
||||
|
||||
$this->db->trans_commit();
|
||||
|
||||
echo json_encode(array(
|
||||
'status' => true,
|
||||
'month' => $month,
|
||||
'processed' => $processed,
|
||||
'message' => 'Monthly attendance generated successfully'
|
||||
));
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
$this->db->trans_rollback();
|
||||
|
||||
echo json_encode(array(
|
||||
'status' => false,
|
||||
'month' => $month,
|
||||
'message' => $e->getMessage()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,6 +3,18 @@ defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Invoices extends CI_Controller {
|
||||
|
||||
|
||||
// =========================
|
||||
// 🔥 CONFIG AKUN
|
||||
// =========================
|
||||
private $akun_persediaan = 21;
|
||||
private $akun_hpp = 63;
|
||||
private $akun_piutang = 19;
|
||||
private $pendapatan_dimuka = 78; // Pendapatan Diterima Dimuka
|
||||
private $persediaan_dijual = 80; // Persediaan Dalam Penjualan
|
||||
private $pendapatan_barang = 62;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
@@ -405,297 +417,6 @@ class Invoices extends CI_Controller {
|
||||
]);
|
||||
}
|
||||
|
||||
public function bayar()
|
||||
{
|
||||
$this->output->set_content_type('application/json');
|
||||
|
||||
$invoice_id = $this->input->post('invoice_id');
|
||||
$tanggal_bayar = $this->input->post('tanggal_bayar');
|
||||
$detail = $this->input->post('detail');
|
||||
|
||||
if(!$invoice_id || empty($detail)){
|
||||
echo json_encode(['status'=>false,'message'=>'Data tidak valid']);
|
||||
return;
|
||||
}
|
||||
|
||||
$invoice = $this->db->get_where('invoices',['id'=>$invoice_id])->row();
|
||||
if(!$invoice){
|
||||
echo json_encode(['status'=>false,'message'=>'Invoice tidak ditemukan']);
|
||||
return;
|
||||
}
|
||||
|
||||
$customer = $this->db->get_where('customers',['id'=>$invoice->customer_id])->row();
|
||||
if(!$customer){
|
||||
echo json_encode(['status'=>false,'message'=>'Customer tidak ditemukan']);
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// HITUNG TOTAL BAYAR
|
||||
// =========================
|
||||
$total_bayar_input = 0;
|
||||
foreach ($detail as $d) {
|
||||
$total_bayar_input += (float)$d['amount'];
|
||||
}
|
||||
|
||||
if($total_bayar_input <= 0){
|
||||
echo json_encode(['status'=>false,'message'=>'Total bayar harus > 0']);
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DATA INVOICE
|
||||
// =========================
|
||||
$paid_before = (float)$invoice->total_bayar;
|
||||
$total_invoice = (float)$invoice->total;
|
||||
|
||||
$new_total_bayar = $paid_before + $total_bayar_input;
|
||||
$sisa_setelah = $total_invoice - $new_total_bayar;
|
||||
|
||||
if($new_total_bayar > $total_invoice){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Pembayaran melebihi total invoice'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// AKUN
|
||||
// =========================
|
||||
$akun_tabungan = 70;
|
||||
$akun_barang = 62;
|
||||
$akun_piutang = 19;
|
||||
|
||||
// =========================
|
||||
// HITUNG TOTAL CICILAN
|
||||
// =========================
|
||||
|
||||
$cicilan = $this->db->query("
|
||||
SELECT ii.*
|
||||
FROM invoice_installments ii
|
||||
JOIN (
|
||||
SELECT invoice_detail_id, MIN(angsuran_ke) as angsuran_ke
|
||||
FROM invoice_installments
|
||||
WHERE customer_id = ?
|
||||
AND status != 'paid'
|
||||
GROUP BY invoice_detail_id
|
||||
) x
|
||||
ON x.invoice_detail_id = ii.invoice_detail_id
|
||||
AND x.angsuran_ke = ii.angsuran_ke
|
||||
", [$customer->id])->result();
|
||||
|
||||
$total_cicilan = 0;
|
||||
|
||||
foreach($cicilan as $c){
|
||||
$total_cicilan += ($c->nominal - $c->paid_amount);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// TOTAL PER KATEGORI
|
||||
// =========================
|
||||
$total_tabungan = (float) $this->db
|
||||
->select('SUM(subtotal) as total')
|
||||
->where('invoice_id', $invoice_id)
|
||||
->where('account_id', $akun_tabungan)
|
||||
->get('invoice_details')->row()->total ?? 0;
|
||||
|
||||
$total_barang = (float) $this->db
|
||||
->select('SUM(subtotal) as total')
|
||||
->where('invoice_id', $invoice_id)
|
||||
->where('account_id', $akun_barang)
|
||||
->get('invoice_details')->row()->total ?? 0;
|
||||
|
||||
$total_other = (float) $this->db
|
||||
->select('SUM(subtotal) as total')
|
||||
->where('invoice_id', $invoice_id)
|
||||
->where_not_in('account_id', [$akun_tabungan, $akun_barang])
|
||||
->get('invoice_details')->row()->total ?? 0;
|
||||
|
||||
// =========================
|
||||
// SISA PER KATEGORI
|
||||
// =========================
|
||||
$sisa_other = max(0, $total_other - $paid_before);
|
||||
$sisa_tabungan = max(0, $total_tabungan - max(0, $paid_before - $total_other));
|
||||
$sisa_barang = max(0, $total_barang - max(0, $paid_before - $total_other - $total_tabungan));
|
||||
|
||||
// =========================
|
||||
// ALOKASI
|
||||
// =========================
|
||||
$sisa_bayar = $total_bayar_input;
|
||||
|
||||
// =========================
|
||||
// 1. CICILAN (PER ITEM)
|
||||
// =========================
|
||||
$bayar_cicilan = min($sisa_bayar, $total_cicilan);
|
||||
$sisa_bayar -= $bayar_cicilan;
|
||||
|
||||
// =========================
|
||||
// 2. OTHER
|
||||
// =========================
|
||||
$bayar_other = min($sisa_bayar, $sisa_other);
|
||||
$sisa_bayar -= $bayar_other;
|
||||
|
||||
// =========================
|
||||
// 3. TABUNGAN
|
||||
// =========================
|
||||
$bayar_tabungan = min($sisa_bayar, $sisa_tabungan);
|
||||
$sisa_bayar -= $bayar_tabungan;
|
||||
|
||||
// =========================
|
||||
// 4. BARANG
|
||||
// =========================
|
||||
$bayar_barang = min($sisa_bayar, $sisa_barang);
|
||||
$sisa_bayar -= $bayar_barang;
|
||||
|
||||
// =========================
|
||||
// TRANSACTION
|
||||
// =========================
|
||||
$this->db->trans_start();
|
||||
|
||||
// UPDATE invoice_installments jika perlu di update
|
||||
if($bayar_cicilan > 0){
|
||||
|
||||
$sisa = $bayar_cicilan; // ✅ FIX
|
||||
|
||||
foreach($cicilan as $c){
|
||||
|
||||
if($sisa <= 0) break;
|
||||
|
||||
$kurang = $c->nominal - $c->paid_amount;
|
||||
$bayar = min($sisa, $kurang);
|
||||
|
||||
$sisa -= $bayar;
|
||||
|
||||
$new_paid = $c->paid_amount + $bayar;
|
||||
$status = ($new_paid >= $c->nominal) ? 'paid' : 'partial';
|
||||
|
||||
$this->db->where('id',$c->id)->update('invoice_installments',[
|
||||
'paid_amount' => $new_paid,
|
||||
'status' => $status
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$no_ref = 'PAY-' . date('YmdHis');
|
||||
|
||||
$this->db->insert('journals', [
|
||||
'tanggal' => $tanggal_bayar,
|
||||
'no_ref' => $no_ref,
|
||||
'keterangan'=> 'Diterima Pembayaran Invoice '.$invoice->no_invoice.' ('.$customer->nama.')',
|
||||
'ref_type' => 'invoice_payment',
|
||||
'ref_id' => $invoice_id,
|
||||
'created_by'=> $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$journal_id = $this->db->insert_id();
|
||||
|
||||
// DEBIT
|
||||
$total_debit = 0;
|
||||
foreach ($detail as $d) {
|
||||
if(empty($d['account_id']) || $d['amount'] <= 0) continue;
|
||||
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $journal_id,
|
||||
'account_id' => $d['account_id'],
|
||||
'debit' => $d['amount'],
|
||||
'kredit' => 0
|
||||
]);
|
||||
|
||||
$total_debit += $d['amount'];
|
||||
}
|
||||
|
||||
// =========================
|
||||
// KREDIT
|
||||
// =========================
|
||||
$total_kredit = 0;
|
||||
|
||||
$kredit_piutang = $bayar_cicilan + $bayar_other + $bayar_barang;
|
||||
|
||||
if($kredit_piutang > 0){
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id'=>$journal_id,
|
||||
'account_id'=>$akun_piutang,
|
||||
'debit'=>0,
|
||||
'kredit'=>$kredit_piutang
|
||||
]);
|
||||
$total_kredit += $kredit_piutang;
|
||||
}
|
||||
|
||||
if($bayar_tabungan > 0){
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id'=>$journal_id,
|
||||
'account_id'=>$akun_tabungan,
|
||||
'debit'=>0,
|
||||
'kredit'=>$bayar_tabungan
|
||||
]);
|
||||
$total_kredit += $bayar_tabungan;
|
||||
}
|
||||
|
||||
// VALIDASI
|
||||
if(round($total_debit,2) !== round($total_kredit,2)){
|
||||
$this->db->trans_rollback();
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Jurnal tidak balance'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// PAYMENT
|
||||
$this->db->insert('payments', [
|
||||
'invoice_id'=>$invoice_id,
|
||||
'tanggal'=>$tanggal_bayar,
|
||||
'jumlah'=>$total_bayar_input,
|
||||
'metode'=>'manual',
|
||||
'journal_id'=>$journal_id
|
||||
]);
|
||||
|
||||
// STATUS
|
||||
if($new_total_bayar >= $total_invoice){
|
||||
$status = 'paid';
|
||||
$sisa_setelah = 0;
|
||||
}elseif($new_total_bayar > 0){
|
||||
$status = 'partial';
|
||||
}else{
|
||||
$status = 'unpaid';
|
||||
}
|
||||
|
||||
$this->db->where('id',$invoice_id)->update('invoices',[
|
||||
'total_bayar'=>$new_total_bayar,
|
||||
'sisa_piutang'=>$sisa_setelah,
|
||||
'status'=>$status,
|
||||
'updated_at'=>date('Y-m-d H:i:s'),
|
||||
'updated_by'=>$this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
// =========================
|
||||
// RESPONSE
|
||||
// =========================
|
||||
if (!$this->db->trans_status()) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Gagal menyelesaikan pembayaran'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
log_activity(
|
||||
'invoice',
|
||||
'create',
|
||||
'Melakukan pembayaran invoice ' . $invoice->no_invoice . ' untuk customer a.n ' . $customer->nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status'=>true,
|
||||
'message'=>'Pembayaran berhasil',
|
||||
'sisa'=>$sisa_setelah
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DELETE
|
||||
// =========================
|
||||
@@ -818,13 +539,6 @@ class Invoices extends CI_Controller {
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// 🔥 CONFIG AKUN
|
||||
// =========================
|
||||
private $akun_persediaan = 21;
|
||||
private $akun_hpp = 63;
|
||||
private $akun_piutang = 19;
|
||||
|
||||
// =========================
|
||||
// ADD ITEM - FIXED RESPONSE
|
||||
// =========================
|
||||
@@ -909,7 +623,8 @@ class Invoices extends CI_Controller {
|
||||
'warehouse_id' => $warehouse_id,
|
||||
'keterangan' => $this->input->post('keterangan'),
|
||||
'subtotal_asli' => $harga_asli,
|
||||
'is_cicilan' => $is_cicilan ? 1 : 0
|
||||
'is_cicilan' => $is_cicilan ? 1 : 0,
|
||||
'total_hpp_barang' => $total_hpp
|
||||
];
|
||||
|
||||
$this->db->insert('invoice_details', $insert_data);
|
||||
@@ -921,6 +636,7 @@ class Invoices extends CI_Controller {
|
||||
if($this->input->post('account_id') != 70) {
|
||||
$this->generate_jurnal_item($detail_id, $ket_cicilan_jr);
|
||||
}
|
||||
|
||||
$this->update_total($invoice_id);
|
||||
|
||||
// ambil customer dari invoice
|
||||
@@ -995,12 +711,15 @@ class Invoices extends CI_Controller {
|
||||
$nama_item = $this->input->post('nama_item');
|
||||
$tanggal = $this->input->post('tanggal');
|
||||
|
||||
$total_hpp = 0;
|
||||
|
||||
if($item_id){
|
||||
$item = $this->db->get_where('items', ['id'=>$item_id])->row();
|
||||
if($item){
|
||||
$nama_item = $item->nama_barang;
|
||||
$stok = $this->get_stok($item_id);
|
||||
$qty = (float)$this->input->post('qty');
|
||||
$total_hpp = $this->input->post('qty') * $item->harga_beli;
|
||||
if($stok < $qty){
|
||||
echo json_encode(['status'=>false, 'message'=>'Stok tidak cukup']);
|
||||
return;
|
||||
@@ -1021,7 +740,8 @@ class Invoices extends CI_Controller {
|
||||
'harga' => $harga,
|
||||
'subtotal' => $qty * $harga,
|
||||
'warehouse_id' => $this->input->post('warehouse_id'),
|
||||
'keterangan' => $this->input->post('keterangan')
|
||||
'keterangan' => $this->input->post('keterangan'),
|
||||
'total_hpp_barang' => $total_hpp
|
||||
];
|
||||
|
||||
$this->db->where('id', $id)->update('invoice_details', $update_data);
|
||||
@@ -1112,60 +832,6 @@ class Invoices extends CI_Controller {
|
||||
echo json_encode($cicilan_raw);
|
||||
}
|
||||
|
||||
// public function save_cicilan()
|
||||
// {
|
||||
// $cicilan_ids = $this->input->post('cicilan_id');
|
||||
|
||||
// if (empty($cicilan_ids)) {
|
||||
// echo json_encode([
|
||||
// 'status' => false,
|
||||
// 'message' => 'Tidak ada data dipilih'
|
||||
// ]);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// $this->db->trans_start();
|
||||
|
||||
// foreach ($cicilan_ids as $id) {
|
||||
|
||||
// // ambil data cicilan
|
||||
// $cicilan = $this->db->get_where('invoice_installments', [
|
||||
// 'id' => $id
|
||||
// ])->row();
|
||||
|
||||
// if (!$cicilan) continue;
|
||||
|
||||
// $sisa = $cicilan->nominal - $cicilan->paid_amount;
|
||||
|
||||
// // insert ke invoice_details
|
||||
// $this->db->insert('invoice_details', [
|
||||
// 'invoice_id' => $cicilan->invoice_id,
|
||||
// 'customer_id' => $cicilan->customer_id,
|
||||
// 'item_id' => $cicilan->item_id,
|
||||
// 'qty' => 1,
|
||||
// 'price' => $sisa,
|
||||
// 'total' => $sisa,
|
||||
// 'source_cicilan_id'=> $cicilan->id, // penting buat tracking
|
||||
// 'created_at' => date('Y-m-d H:i:s')
|
||||
// ]);
|
||||
|
||||
// // update status cicilan jadi billed
|
||||
// $this->db->update('invoice_installments', [
|
||||
// 'is_billed' => 1
|
||||
// ], ['id' => $id]);
|
||||
// }
|
||||
|
||||
// $this->db->trans_complete();
|
||||
|
||||
// echo json_encode([
|
||||
// 'status' => $this->db->trans_status()
|
||||
// ]);
|
||||
// }
|
||||
// =========================
|
||||
// HAPUS HELPER LAMA - TIDAK DIPAKAI LAGI
|
||||
// =========================
|
||||
// Hapus fungsi commit() & rollback() karena sudah inline
|
||||
|
||||
private function generate_jurnal_item($id, $ket_cicilan_jr = null)
|
||||
{
|
||||
// $d = $this->db->get_where('invoice_details', ['id'=>$id])->row();
|
||||
@@ -1254,11 +920,11 @@ class Invoices extends CI_Controller {
|
||||
]);
|
||||
|
||||
// =========================
|
||||
// 🔥 PENDAPATAN (KREDIT)
|
||||
// 🔥 PENDAPATAN (KREDIT) Pendapatan Diterima Dimuka
|
||||
// =========================
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $jid,
|
||||
'account_id' => $d->account_id,
|
||||
'account_id' => $this->pendapatan_dimuka,
|
||||
'debit' => 0,
|
||||
'kredit' => $nilai_jurnal
|
||||
]);
|
||||
@@ -1271,7 +937,7 @@ class Invoices extends CI_Controller {
|
||||
// HPP (debit)
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $jid,
|
||||
'account_id' => $this->akun_hpp,
|
||||
'account_id' => $this->persediaan_dijual,
|
||||
'debit' => $total_hpp,
|
||||
'kredit' => 0
|
||||
]);
|
||||
@@ -1689,4 +1355,495 @@ class Invoices extends CI_Controller {
|
||||
'status' => $this->db->trans_status()
|
||||
]);
|
||||
}
|
||||
|
||||
public function bayar()
|
||||
{
|
||||
$this->output->set_content_type('application/json');
|
||||
|
||||
$invoice_id = $this->input->post('invoice_id');
|
||||
$tanggal_bayar = $this->input->post('tanggal_bayar');
|
||||
$detail = $this->input->post('detail');
|
||||
|
||||
if (!$invoice_id || empty($detail)) {
|
||||
echo json_encode(['status' => false, 'message' => 'Data tidak valid']);
|
||||
return;
|
||||
}
|
||||
|
||||
$invoice = $this->db->get_where('invoices', ['id' => $invoice_id])->row();
|
||||
if (!$invoice) {
|
||||
echo json_encode(['status' => false, 'message' => 'Invoice tidak ditemukan']);
|
||||
return;
|
||||
}
|
||||
|
||||
$customer = $this->db->get_where('customers', ['id' => $invoice->customer_id])->row();
|
||||
if (!$customer) {
|
||||
echo json_encode(['status' => false, 'message' => 'Customer tidak ditemukan']);
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// HITUNG TOTAL BAYAR
|
||||
// =========================
|
||||
$total_bayar_input = 0;
|
||||
foreach ($detail as $d) {
|
||||
$total_bayar_input += (float)$d['amount'];
|
||||
}
|
||||
|
||||
if ($total_bayar_input <= 0) {
|
||||
echo json_encode(['status' => false, 'message' => 'Total bayar harus > 0']);
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DATA INVOICE
|
||||
// =========================
|
||||
$paid_before = (float)$invoice->total_bayar;
|
||||
$total_invoice = (float)$invoice->total;
|
||||
$new_total_bayar = $paid_before + $total_bayar_input;
|
||||
$sisa_setelah = $total_invoice - $new_total_bayar;
|
||||
|
||||
if ($new_total_bayar > $total_invoice) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Pembayaran melebihi total invoice'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// KONFIGURASI AKUN
|
||||
// =========================
|
||||
$akun_tabungan = 70;
|
||||
$akun_barang = 62;
|
||||
$akun_piutang = 19;
|
||||
$akun_pendapatan_ditahan = 78;
|
||||
$akun_hpp = isset($this->akun_hpp) ? $this->akun_hpp : 81;
|
||||
$persediaan_dijual = isset($this->persediaan_dijual) ? $this->persediaan_dijual : 50;
|
||||
|
||||
// =========================
|
||||
// HITUNG CICILAN
|
||||
// =========================
|
||||
$cicilan = $this->db->query("
|
||||
SELECT ii.*
|
||||
FROM invoice_installments ii
|
||||
JOIN (
|
||||
SELECT invoice_detail_id, MIN(angsuran_ke) as angsuran_ke
|
||||
FROM invoice_installments
|
||||
WHERE customer_id = ?
|
||||
AND status != 'paid'
|
||||
GROUP BY invoice_detail_id
|
||||
) x
|
||||
ON x.invoice_detail_id = ii.invoice_detail_id
|
||||
AND x.angsuran_ke = ii.angsuran_ke
|
||||
", [$customer->id])->result();
|
||||
|
||||
$total_cicilan = 0;
|
||||
foreach ($cicilan as $c) {
|
||||
$total_cicilan += ($c->nominal - $c->paid_amount);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// TOTAL PER KATEGORI
|
||||
// =========================
|
||||
$total_tabungan = (float)$this->db
|
||||
->select('SUM(subtotal) as total')
|
||||
->where('invoice_id', $invoice_id)
|
||||
->where('account_id', $akun_tabungan)
|
||||
->get('invoice_details')->row()->total ?? 0;
|
||||
|
||||
$total_barang = (float)$this->db
|
||||
->select('SUM(subtotal) as total')
|
||||
->where('invoice_id', $invoice_id)
|
||||
->where('account_id', $akun_barang)
|
||||
->get('invoice_details')->row()->total ?? 0;
|
||||
|
||||
$total_other = (float)$this->db
|
||||
->select('SUM(subtotal) as total')
|
||||
->where('invoice_id', $invoice_id)
|
||||
->where_not_in('account_id', [$akun_tabungan, $akun_barang])
|
||||
->get('invoice_details')->row()->total ?? 0;
|
||||
|
||||
// =========================
|
||||
// SISA PER KATEGORI
|
||||
// =========================
|
||||
$sisa_other = max(0, $total_other - $paid_before);
|
||||
$sisa_tabungan = max(0, $total_tabungan - max(0, $paid_before - $total_other));
|
||||
$sisa_barang = max(0, $total_barang - max(0, $paid_before - $total_other - $total_tabungan));
|
||||
|
||||
// =========================
|
||||
// ALOKASI PEMBAYARAN
|
||||
// =========================
|
||||
$sisa_bayar = $total_bayar_input;
|
||||
|
||||
$bayar_cicilan = min($sisa_bayar, $total_cicilan);
|
||||
$sisa_bayar -= $bayar_cicilan;
|
||||
|
||||
$bayar_other = min($sisa_bayar, $sisa_other);
|
||||
$sisa_bayar -= $bayar_other;
|
||||
|
||||
$bayar_tabungan = min($sisa_bayar, $sisa_tabungan);
|
||||
$sisa_bayar -= $bayar_tabungan;
|
||||
|
||||
$bayar_barang = min($sisa_bayar, $sisa_barang);
|
||||
$sisa_bayar -= $bayar_barang;
|
||||
|
||||
// =========================
|
||||
// AMBIL INVOICE DETAIL
|
||||
// =========================
|
||||
$inv_detail_items = $this->db
|
||||
->select('
|
||||
invoice_details.id,
|
||||
invoice_details.account_id,
|
||||
invoice_details.subtotal,
|
||||
invoice_details.recognized_amount,
|
||||
invoice_details.total_hpp_barang,
|
||||
invoice_details.recognized_hpp,
|
||||
accounts.priority
|
||||
')
|
||||
->from('invoice_details')
|
||||
->join('accounts', 'accounts.id = invoice_details.account_id', 'left')
|
||||
->where('invoice_details.invoice_id', $invoice_id)
|
||||
->where('invoice_details.account_id !=', $akun_tabungan)
|
||||
->order_by('accounts.priority', 'ASC')
|
||||
->order_by('invoice_details.id', 'ASC')
|
||||
->get()
|
||||
->result();
|
||||
|
||||
// =========================
|
||||
// DEBIT PENDAPATAN DITAHAN
|
||||
// =========================
|
||||
// Tidak termasuk tabungan!
|
||||
$debit_pendapatan_ditahan = $bayar_cicilan + $bayar_other + $bayar_barang;
|
||||
|
||||
// =========================
|
||||
// MULAI TRANSAKSI
|
||||
// =========================
|
||||
$this->db->trans_start();
|
||||
|
||||
// UPDATE cicilan
|
||||
if ($bayar_cicilan > 0) {
|
||||
$sisa = $bayar_cicilan;
|
||||
foreach ($cicilan as $c) {
|
||||
if ($sisa <= 0) break;
|
||||
$kurang = $c->nominal - $c->paid_amount;
|
||||
$bayar = min($sisa, $kurang);
|
||||
$sisa -= $bayar;
|
||||
$new_paid = $c->paid_amount + $bayar;
|
||||
$status = ($new_paid >= $c->nominal) ? 'paid' : 'partial';
|
||||
|
||||
$this->db->where('id', $c->id)->update('invoice_installments', [
|
||||
'paid_amount' => $new_paid,
|
||||
'status' => $status
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$no_ref = 'PAY-' . date('YmdHis');
|
||||
|
||||
$this->db->insert('journals', [
|
||||
'tanggal' => $tanggal_bayar,
|
||||
'no_ref' => $no_ref,
|
||||
'keterangan'=> 'Pembayaran Invoice ' . $invoice->no_invoice . ' (' . $customer->nama . ')',
|
||||
'ref_type' => 'invoice_payment',
|
||||
'ref_id' => $invoice_id,
|
||||
'created_by'=> $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$journal_id = $this->db->insert_id();
|
||||
|
||||
// =========================
|
||||
// DEBIT SIDE
|
||||
// =========================
|
||||
$total_debit = 0;
|
||||
$jurnal_debit = [];
|
||||
|
||||
// 1. Kas/Bank (dari detail)
|
||||
foreach ($detail as $d) {
|
||||
if (empty($d['account_id']) || $d['amount'] <= 0) continue;
|
||||
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $journal_id,
|
||||
'account_id' => $d['account_id'],
|
||||
'debit' => $d['amount'],
|
||||
'kredit' => 0
|
||||
]);
|
||||
|
||||
$total_debit += (float)$d['amount'];
|
||||
$jurnal_debit[] = [
|
||||
'account_id' => $d['account_id'],
|
||||
'debit' => (float)$d['amount'],
|
||||
'jenis' => 'kas'
|
||||
];
|
||||
}
|
||||
|
||||
// =========================
|
||||
// KREDIT SIDE
|
||||
// =========================
|
||||
$total_kredit = 0;
|
||||
$jurnal_kredit = [];
|
||||
|
||||
// 1. Piutang (KREDIT)
|
||||
$kredit_piutang = $total_bayar_input - $bayar_tabungan;
|
||||
if ($kredit_piutang > 0) {
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $journal_id,
|
||||
'account_id' => $akun_piutang,
|
||||
'debit' => 0,
|
||||
'kredit' => $kredit_piutang
|
||||
]);
|
||||
$total_kredit += $kredit_piutang;
|
||||
$jurnal_kredit[] = [
|
||||
'account_id' => $akun_piutang,
|
||||
'kredit' => $kredit_piutang,
|
||||
'jenis' => 'piutang'
|
||||
];
|
||||
}
|
||||
|
||||
// 2. Tabungan (KREDIT)
|
||||
if ($bayar_tabungan > 0) {
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $journal_id,
|
||||
'account_id' => $akun_tabungan,
|
||||
'debit' => 0,
|
||||
'kredit' => $bayar_tabungan
|
||||
]);
|
||||
$total_kredit += $bayar_tabungan;
|
||||
$jurnal_kredit[] = [
|
||||
'account_id' => $akun_tabungan,
|
||||
'kredit' => $bayar_tabungan,
|
||||
'jenis' => 'tabungan'
|
||||
];
|
||||
}
|
||||
|
||||
// =========================
|
||||
// PENGAKUAN PENDAPATAN & HPP
|
||||
// =========================
|
||||
$sisa_pengakuan = $bayar_cicilan + $bayar_other + $bayar_barang;
|
||||
$account_recognition = [];
|
||||
$total_hpp = 0;
|
||||
|
||||
foreach ($inv_detail_items as $i) {
|
||||
if ($sisa_pengakuan <= 0) break;
|
||||
|
||||
$belum_diakui = (float)$i->subtotal - (float)$i->recognized_amount;
|
||||
if ($belum_diakui <= 0) continue;
|
||||
|
||||
$nominal = min($sisa_pengakuan, $belum_diakui);
|
||||
|
||||
if (!isset($account_recognition[$i->account_id])) {
|
||||
$account_recognition[$i->account_id] = 0;
|
||||
}
|
||||
$account_recognition[$i->account_id] += $nominal;
|
||||
|
||||
// Update recognized amount
|
||||
$this->db->query("
|
||||
UPDATE invoice_details
|
||||
SET recognized_amount = recognized_amount + ?
|
||||
WHERE id = ?
|
||||
", [$nominal, $i->id]);
|
||||
|
||||
if ($i->account_id == $akun_barang ) {
|
||||
|
||||
$persentase = $nominal / (float)$i->subtotal;
|
||||
$hpp_item = (float)$i->total_hpp_barang * $persentase;
|
||||
$hpp_item = round($hpp_item, 2);
|
||||
|
||||
$sisa_hpp = max(0, (float)$i->total_hpp_barang - (float)$i->recognized_hpp);
|
||||
$hpp_item = min($hpp_item, $sisa_hpp);
|
||||
|
||||
if ($hpp_item > 0) {
|
||||
// Cara 1: Pakai update() method
|
||||
$this->db->where('id', $i->id);
|
||||
$this->db->update('invoice_details', [
|
||||
'recognized_hpp' => $i->recognized_hpp + $hpp_item
|
||||
]);
|
||||
|
||||
$total_hpp += $hpp_item;
|
||||
}
|
||||
}
|
||||
|
||||
$sisa_pengakuan -= $nominal;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// ALOKASI SISA KE AKUN LAIN
|
||||
// =========================
|
||||
$total_diaku = array_sum($account_recognition);
|
||||
$sisa_yg_harus_diaku = $bayar_cicilan + $bayar_other + $bayar_barang;
|
||||
$selisih_alokasi = $sisa_yg_harus_diaku - $total_diaku;
|
||||
|
||||
if ($selisih_alokasi > 0) {
|
||||
$akun_other_list = $this->db
|
||||
->select('account_id, SUM(subtotal) as total')
|
||||
->from('invoice_details')
|
||||
->where('invoice_id', $invoice_id)
|
||||
->where_not_in('account_id', [$akun_tabungan, $akun_barang])
|
||||
->group_by('account_id')
|
||||
->get()
|
||||
->result();
|
||||
|
||||
foreach ($akun_other_list as $ao) {
|
||||
if ($selisih_alokasi <= 0) break;
|
||||
|
||||
$belum_diaku_akun = (float)$ao->total;
|
||||
$alokasi = min($selisih_alokasi, $belum_diaku_akun);
|
||||
|
||||
if (!isset($account_recognition[$ao->account_id])) {
|
||||
$account_recognition[$ao->account_id] = 0;
|
||||
}
|
||||
$account_recognition[$ao->account_id] += $alokasi;
|
||||
|
||||
$selisih_alokasi -= $alokasi;
|
||||
}
|
||||
}
|
||||
|
||||
// =========================
|
||||
// Insert DEBIT pendapatan
|
||||
// =========================
|
||||
if ($debit_pendapatan_ditahan > 0) {
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $journal_id,
|
||||
'account_id' => $akun_pendapatan_ditahan,
|
||||
'debit' => $debit_pendapatan_ditahan,
|
||||
'kredit' => 0
|
||||
]);
|
||||
|
||||
$total_debit += $debit_pendapatan_ditahan;
|
||||
$jurnal_debit[] = [
|
||||
'account_id' => $akun_pendapatan_ditahan,
|
||||
'debit' => $debit_pendapatan_ditahan,
|
||||
'jenis' => 'pendapatan_ditahan'
|
||||
];
|
||||
}
|
||||
|
||||
// =========================
|
||||
// Insert KREDIT pendapatan
|
||||
// =========================
|
||||
foreach ($account_recognition as $account_id => $nominal) {
|
||||
if ($nominal <= 0) continue;
|
||||
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $journal_id,
|
||||
'account_id' => $account_id,
|
||||
'debit' => 0,
|
||||
'kredit' => $nominal
|
||||
]);
|
||||
|
||||
$total_kredit += $nominal;
|
||||
$jurnal_kredit[] = [
|
||||
'account_id' => $account_id,
|
||||
'kredit' => $nominal,
|
||||
'jenis' => 'pendapatan'
|
||||
];
|
||||
}
|
||||
|
||||
// =========================
|
||||
// JURNAL HPP
|
||||
// =========================
|
||||
if ($total_hpp > 0) {
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $journal_id,
|
||||
'account_id' => $akun_hpp,
|
||||
'debit' => $total_hpp,
|
||||
'kredit' => 0
|
||||
]);
|
||||
$total_debit += $total_hpp;
|
||||
|
||||
$jurnal_debit[] = [
|
||||
'account_id' => $akun_hpp,
|
||||
'debit' => $total_hpp,
|
||||
'jenis' => 'hpp_barang'
|
||||
];
|
||||
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $journal_id,
|
||||
'account_id' => $persediaan_dijual,
|
||||
'debit' => 0,
|
||||
'kredit' => $total_hpp
|
||||
]);
|
||||
$total_kredit += $total_hpp;
|
||||
|
||||
|
||||
$jurnal_kredit[] = [
|
||||
'account_id' => $persediaan_dijual,
|
||||
'kredit' => $total_hpp,
|
||||
'jenis' => 'persediaan_dijual'
|
||||
];
|
||||
}
|
||||
|
||||
// =========================
|
||||
// VALIDASI JURNAL
|
||||
// =========================
|
||||
if (round($total_debit, 2) !== round($total_kredit, 2)) {
|
||||
$this->db->trans_rollback();
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Jurnal tidak balance!'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// INSERT PAYMENTS
|
||||
// =========================
|
||||
$this->db->insert('payments', [
|
||||
'invoice_id' => $invoice_id,
|
||||
'tanggal' => $tanggal_bayar,
|
||||
'jumlah' => $total_bayar_input,
|
||||
'metode' => 'manual',
|
||||
'journal_id'=> $journal_id
|
||||
]);
|
||||
|
||||
// =========================
|
||||
// UPDATE STATUS INVOICE
|
||||
// =========================
|
||||
if ($new_total_bayar >= $total_invoice) {
|
||||
$status = 'paid';
|
||||
$sisa_setelah = 0;
|
||||
} elseif ($new_total_bayar > 0) {
|
||||
$status = 'partial';
|
||||
} else {
|
||||
$status = 'unpaid';
|
||||
}
|
||||
|
||||
$this->db->where('id', $invoice_id)->update('invoices', [
|
||||
'total_bayar' => $new_total_bayar,
|
||||
'sisa_piutang' => $sisa_setelah,
|
||||
'status' => $status,
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
'updated_by' => $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
// =========================
|
||||
// SELESAIKAN TRANSAKSI
|
||||
// =========================
|
||||
$this->db->trans_complete();
|
||||
|
||||
// =========================
|
||||
// RESPONSE
|
||||
// =========================
|
||||
if (!$this->db->trans_status()) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Gagal menyelesaikan pembayaran'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Logging
|
||||
log_activity(
|
||||
'invoice',
|
||||
'create',
|
||||
'Pembayaran invoice ' . $invoice->no_invoice . ' - ' . $customer->nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Pembayaran berhasil'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -141,13 +141,13 @@ class Jurnal extends CI_Controller {
|
||||
$debit = $this->input->post('debit');
|
||||
$kredit = $this->input->post('kredit');
|
||||
|
||||
if (array_sum($debit) != array_sum($kredit)) {
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Debit & Kredit tidak balance!'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
if (array_sum($debit) != array_sum($kredit)) {
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Debit & Kredit tidak balance!'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
|
||||
@@ -0,0 +1,431 @@
|
||||
<style>
|
||||
.calendar-grid{
|
||||
display:grid;
|
||||
grid-template-columns:repeat(7,1fr);
|
||||
gap:8px;
|
||||
}
|
||||
|
||||
.calendar-card{
|
||||
min-height:60px;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
.calendar-card.empty{
|
||||
visibility:hidden;
|
||||
}
|
||||
|
||||
.calendar-card .badge{
|
||||
font-size:10px;
|
||||
}
|
||||
|
||||
.badge-custom {
|
||||
background-color: #ff8874;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.badge-custom1{
|
||||
background-color: #27F549;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.badge-custom2 {
|
||||
background-color: #CB21FF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.badge-custom3 {
|
||||
background-color: #94A600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.badge-custom4 {
|
||||
background-color: #8200C7;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="container mt-4">
|
||||
|
||||
<div class="card border-0 shadow-sm rounded-4">
|
||||
|
||||
<div class="card-body p-4">
|
||||
|
||||
<div class="d-flex justify-content-end align-items-center mb-3">
|
||||
<h7 class="mb-0">Tanggal</h7>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
|
||||
|
||||
<h5 class="mb-0">
|
||||
Monitoring Absensi Bulanan
|
||||
</h5>
|
||||
|
||||
<input type="month"
|
||||
id="filterMonth"
|
||||
class="form-control"
|
||||
style="max-width:220px"
|
||||
value="<?= date('Y-m') ?>">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<table id="tableAttendance"
|
||||
class="table modern-table align-middle w-100">
|
||||
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Kode</th>
|
||||
<th>Nama</th>
|
||||
<th>Periode</th>
|
||||
<th>Status</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- MODAL DETAIL -->
|
||||
<div class="modal fade" id="modalDetail">
|
||||
<div class="modal-dialog modal-xl modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-warning text-white">
|
||||
<h5>Detail Absensi Bulanan</h5>
|
||||
<button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<table class="table mb-3">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="180">No</th>
|
||||
<td><span id="d_id"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Kode Karyawan</th>
|
||||
<td><span id="d_employee_code"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Nama Karyawan</th>
|
||||
<td><span id="d_full_name"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Periode</th>
|
||||
<td><span id="d_month"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<td><span id="d_status"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Score</th>
|
||||
<td><span id="d_score"></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<table class="table mb-3">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="100"><span class="badge bg-success">Hadir</span></th>
|
||||
<td id="d_present_count"></td>
|
||||
<th width="180">Hari</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge bg-info">Sakit</span></th>
|
||||
<td id="d_sick_count"></td>
|
||||
<th width="180">Hari</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge bg-primary">Izin</span></th>
|
||||
<td id="d_total_permit"></td>
|
||||
<th width="180">Hari</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge bg-danger">Alpha</span></th>
|
||||
<td id="d_absent_count"></td>
|
||||
<th width="180">Hari</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge bg-warning">Terlambat</span></th>
|
||||
<td id="d_late_count"></td>
|
||||
<th width="180">Menit</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge badge-custom">Total Early Leave Minutes</span></th>
|
||||
<td id="d_total_early_leave_minutes"></td>
|
||||
<th width="180">Menit</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<table class="table mb-3">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="100"><span class="badge badge-custom1">Total Hari Kerja</span></th>
|
||||
<td id="d_total_hari_kerja"></td>
|
||||
<th width="180">Hari</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge bg-dark">Cuti</span></th>
|
||||
<td id="d_total_annual"></td>
|
||||
<th width="180">Hari</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge bg-secondary">Total Jam Kerja</span></th>
|
||||
<td id="d_total_work_hours"></td>
|
||||
<th width="180">Jam</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge badge-custom2">Total Late Minutes</span></th>
|
||||
<td id="d_total_late_minutes"></td>
|
||||
<th width="180">Menit</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge badge-custom4">Total Overtime Hours</span></th>
|
||||
<td id="d_total_overtime_hours"></td>
|
||||
<th width="180">Jam</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><span class="badge badge-custom3">Total Alpha</span></th>
|
||||
<td id="d_total_alpha"></td>
|
||||
<th width="180">Hari</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="border-top my-3"></div>
|
||||
<div id="detailContent"> // VIEW DETAIL ABSENSI BULANAN (DI-GENERATE DARI JS)
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
let table = $('#tableAttendance').DataTable({
|
||||
ajax:{
|
||||
url:`<?= base_url(); ?>attendancemonthly/get_data`,
|
||||
data:function(d){
|
||||
d.date = $('#filterMonth').val();
|
||||
},
|
||||
dataSrc:'data'
|
||||
},
|
||||
columns:[
|
||||
{data:0},
|
||||
{data:1},
|
||||
{data:2},
|
||||
{data:3},
|
||||
{data:4},
|
||||
{data:5}
|
||||
|
||||
]
|
||||
});
|
||||
|
||||
$('#filterMonth').change(function(){
|
||||
table.ajax.reload();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$(function () {
|
||||
|
||||
$(document).on('click', '.btn-detail', function () {
|
||||
|
||||
let id = $(this).data('id');
|
||||
let month = $(this).data('month');
|
||||
|
||||
$.get(
|
||||
`<?= base_url(); ?>attendancemonthly/detail/${id}/${month}`,
|
||||
function (res) {
|
||||
|
||||
// Header
|
||||
$('#d_id').text(res.header.id);
|
||||
$('#d_employee_code').text(res.header.employee_code);
|
||||
$('#d_full_name').text(res.header.full_name);
|
||||
$('#d_month').text(res.header.month);
|
||||
$('#d_status').text(res.header.status);
|
||||
|
||||
// Header - perhitungan
|
||||
$('#d_total_hari_kerja').text(res.header.total_hari_kerja);
|
||||
$('#d_present_count').text(res.header.total_present);
|
||||
$('#d_total_hadir').text(res.header.total_hadir);
|
||||
$('#d_late_count').text(res.header.total_late);
|
||||
$('#d_total_permit').text(res.header.total_permit);
|
||||
|
||||
|
||||
$('#d_sick_count').text(res.header.total_sick);
|
||||
$('#d_total_overtime_hours').text(res.header.total_overtime_hours);
|
||||
$('#d_total_work_hours').text(res.header.total_work_hours);
|
||||
$('#d_total_annual').text(res.header.total_annual);
|
||||
$('#d_total_late_minutes').text(res.header.total_late_minutes);
|
||||
$('#d_total_early_leave_minutes').text(res.header.total_early_leave_minutes);
|
||||
|
||||
$('#d_score').text(res.header.score);
|
||||
$('#d_leave_count').text(res.header.total_leave);
|
||||
$('#d_absent_count').text(res.header.total_alpha);
|
||||
$('#d_late_count').text(res.header.total_late);
|
||||
$('#d_total_alpha').text(res.header.total_alpha);
|
||||
|
||||
|
||||
// Mapping data absensi berdasarkan tanggal
|
||||
let attendanceMap = {};
|
||||
|
||||
$.each(res.detail, function (i, row) {
|
||||
attendanceMap[row.attendance_date] = row;
|
||||
});
|
||||
|
||||
// Ambil bulan dari header
|
||||
let monthDate = new Date(res.header.month);
|
||||
let year = monthDate.getFullYear();
|
||||
let month = monthDate.getMonth();
|
||||
|
||||
// Hari pertama bulan
|
||||
let firstDay = new Date(year, month, 1);
|
||||
|
||||
// Jumlah hari dalam bulan
|
||||
let daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||
|
||||
// Konversi agar minggu dimulai Senin
|
||||
let startDay = firstDay.getDay();
|
||||
startDay = startDay === 0 ? 6 : startDay - 1;
|
||||
|
||||
let html = `
|
||||
<div class="calendar-wrapper">
|
||||
|
||||
<div class="row g-1 fw-bold text-center mb-2">
|
||||
<div class="col">Sen</div>
|
||||
<div class="col">Sel</div>
|
||||
<div class="col">Rab</div>
|
||||
<div class="col">Kam</div>
|
||||
<div class="col">Jum</div>
|
||||
<div class="col">Sab</div>
|
||||
<div class="col">Min</div>
|
||||
</div>
|
||||
|
||||
<div class="calendar-grid">
|
||||
`;
|
||||
|
||||
// Kosong sebelum tanggal 1
|
||||
for (let i = 0; i < startDay; i++) {
|
||||
html += `<div class="calendar-card empty"></div>`;
|
||||
}
|
||||
|
||||
// Isi tanggal
|
||||
for (let day = 1; day <= daysInMonth; day++) {
|
||||
|
||||
let dateStr =
|
||||
`${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
||||
|
||||
let data = attendanceMap[dateStr];
|
||||
|
||||
let badge = '';
|
||||
let cardClass = '';
|
||||
|
||||
if (data) {
|
||||
|
||||
switch (data.attendance_status) {
|
||||
case 'present':
|
||||
badge = '<span class="badge bg-success">Hadir</span>';
|
||||
cardClass = 'border-success';
|
||||
break;
|
||||
|
||||
case 'late':
|
||||
badge = '<span class="badge bg-warning">Terlambat</span>';
|
||||
cardClass = 'border-warning';
|
||||
break;
|
||||
|
||||
case 'alpha':
|
||||
badge = '<span class="badge bg-danger">Alpha</span>';
|
||||
cardClass = 'border-danger';
|
||||
break;
|
||||
|
||||
case 'sick':
|
||||
badge = '<span class="badge bg-info">Sakit</span>';
|
||||
cardClass = 'border-info';
|
||||
break;
|
||||
|
||||
case 'permit':
|
||||
badge = '<span class="badge bg-secondary">Izin</span>';
|
||||
cardClass = 'border-secondary';
|
||||
break;
|
||||
|
||||
case 'annual':
|
||||
badge = '<span class="badge bg-dark">Cuti</span>';
|
||||
cardClass = 'border-dark';
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
html += `
|
||||
<div class="calendar-card card ${cardClass}">
|
||||
<div class="card-body p-2">
|
||||
<div class="row gx-0">
|
||||
<div class="col-auto">
|
||||
<div class="fw-bold" style="font-size: 16px;">${day}</div>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<div class="m-0">${badge}</div>
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted d-block mt-1" style="font-size:15px;">
|
||||
${data.shift_name}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
} else {
|
||||
|
||||
html += `
|
||||
<div class="calendar-card card">
|
||||
<div class="card-body p-2">
|
||||
<div class="fw-bold" style="font-size: 16px;">${day}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
html += `
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
$('#detailContent').html(html);
|
||||
|
||||
|
||||
// Bootstrap 5
|
||||
let modal = new bootstrap.Modal(document.getElementById('modalDetail'));
|
||||
modal.show();
|
||||
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -398,17 +398,21 @@ $('#btnSimpan').click(function(){
|
||||
return;
|
||||
}
|
||||
|
||||
if(totalDebit === 0 && totalKredit === 0){
|
||||
Swal.fire('Warning','Harap Isi Semua Kolom!','warning'); // ✅ FIX add all collumn must be filled
|
||||
return;
|
||||
}
|
||||
|
||||
if($('#keterangan').val().trim() === ''){
|
||||
Swal.fire('Warning','Keterangan tidak boleh kosong!','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$('#tanggal').val()){
|
||||
Swal.fire('Warning','Tanggal wajib diisi!','warning'); // ✅ FIX tambah validasi tanggal
|
||||
Swal.fire('Warning','Tanggal tidak boleh kosong!','warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$('#keterangan').val()){
|
||||
Swal.fire('Warning','Keterangan wajib diisi!','warning'); // ✅ FIX tambah validasi keterangan
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// lanjut simpan
|
||||
$.post("<?= base_url('jurnal/save'); ?>", {
|
||||
tanggal: $('#tanggal').val(),
|
||||
|
||||
@@ -258,17 +258,24 @@
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
<a class="dropdown-item rounded-3 <?= ($active_menu == 'attendance_monitoring') ? 'active' : '' ?>"
|
||||
href="<?= base_url('attendancemonitoring'); ?>">
|
||||
|
||||
<i class="bi bi-fingerprint me-2"></i>
|
||||
Monitoring Absensi
|
||||
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a class="dropdown-item rounded-3 <?= ($active_menu == 'attendance_monthly') ? 'active' : '' ?>"
|
||||
href="<?= base_url('attendancemonthly'); ?>">
|
||||
|
||||
<i class="bi bi-calendar2-date me-2"></i>
|
||||
Absensi Bulanan
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
<hr class="dropdown-divider">
|
||||
<li>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user