Initial commit
@@ -0,0 +1,15 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# Matches multiple files with brace expansion notation
|
||||
# Set default charset
|
||||
[*]
|
||||
charset = utf-8
|
||||
|
||||
# Tab indentation (no size specified)
|
||||
indent_style = tab
|
||||
@@ -0,0 +1,30 @@
|
||||
.DS_Store
|
||||
|
||||
application/cache/*
|
||||
!application/cache/index.html
|
||||
|
||||
application/logs/*
|
||||
!application/logs/index.html
|
||||
|
||||
!application/*/.htaccess
|
||||
|
||||
tests/mocks/database/ci_test.sqlite
|
||||
|
||||
user_guide_src/build/*
|
||||
user_guide_src/cilexer/build/*
|
||||
user_guide_src/cilexer/dist/*
|
||||
user_guide_src/cilexer/pycilexer.egg-info/*
|
||||
|
||||
# IDE Files
|
||||
#-------------------------
|
||||
/nbproject/
|
||||
.idea/*
|
||||
|
||||
## Sublime Text cache files
|
||||
*.tmlanguage.cache
|
||||
*.tmPreferences.cache
|
||||
*.stTheme.cache
|
||||
*.sublime-workspace
|
||||
*.sublime-project
|
||||
/tests/tests/
|
||||
/tests/results/
|
||||
@@ -0,0 +1,9 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
|
||||
# Redirect requests to index.php
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||
</IfModule>
|
||||
@@ -0,0 +1,6 @@
|
||||
<IfModule authz_core_module>
|
||||
Require all denied
|
||||
</IfModule>
|
||||
<IfModule !authz_core_module>
|
||||
Deny from all
|
||||
</IfModule>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| AUTO-LOADER
|
||||
| -------------------------------------------------------------------
|
||||
| This file specifies which systems should be loaded by default.
|
||||
|
|
||||
| In order to keep the framework as light-weight as possible only the
|
||||
| absolute minimal resources are loaded by default. For example,
|
||||
| the database is not connected to automatically since no assumption
|
||||
| is made regarding whether you intend to use it. This file lets
|
||||
| you globally define which systems you would like loaded with every
|
||||
| request.
|
||||
|
|
||||
| -------------------------------------------------------------------
|
||||
| Instructions
|
||||
| -------------------------------------------------------------------
|
||||
|
|
||||
| These are the things you can load automatically:
|
||||
|
|
||||
| 1. Packages
|
||||
| 2. Libraries
|
||||
| 3. Drivers
|
||||
| 4. Helper files
|
||||
| 5. Custom config files
|
||||
| 6. Language files
|
||||
| 7. Models
|
||||
|
|
||||
*/
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| Auto-load Packages
|
||||
| -------------------------------------------------------------------
|
||||
| Prototype:
|
||||
|
|
||||
| $autoload['packages'] = array(APPPATH.'third_party', '/usr/local/shared');
|
||||
|
|
||||
*/
|
||||
$autoload['packages'] = array();
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| Auto-load Libraries
|
||||
| -------------------------------------------------------------------
|
||||
| These are the classes located in system/libraries/ or your
|
||||
| application/libraries/ directory, with the addition of the
|
||||
| 'database' library, which is somewhat of a special case.
|
||||
|
|
||||
| Prototype:
|
||||
|
|
||||
| $autoload['libraries'] = array('database', 'email', 'session');
|
||||
|
|
||||
| You can also supply an alternative library name to be assigned
|
||||
| in the controller:
|
||||
|
|
||||
| $autoload['libraries'] = array('user_agent' => 'ua');
|
||||
*/
|
||||
$autoload['libraries'] = array('session', 'database');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| Auto-load Drivers
|
||||
| -------------------------------------------------------------------
|
||||
| These classes are located in system/libraries/ or in your
|
||||
| application/libraries/ directory, but are also placed inside their
|
||||
| own subdirectory and they extend the CI_Driver_Library class. They
|
||||
| offer multiple interchangeable driver options.
|
||||
|
|
||||
| Prototype:
|
||||
|
|
||||
| $autoload['drivers'] = array('cache');
|
||||
|
|
||||
| You can also supply an alternative property name to be assigned in
|
||||
| the controller:
|
||||
|
|
||||
| $autoload['drivers'] = array('cache' => 'cch');
|
||||
|
|
||||
*/
|
||||
$autoload['drivers'] = array();
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| Auto-load Helper Files
|
||||
| -------------------------------------------------------------------
|
||||
| Prototype:
|
||||
|
|
||||
| $autoload['helper'] = array('url', 'file');
|
||||
*/
|
||||
$autoload['helper'] = array('url', 'file', 'permission', 'activity', 'indo_date');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| Auto-load Config files
|
||||
| -------------------------------------------------------------------
|
||||
| Prototype:
|
||||
|
|
||||
| $autoload['config'] = array('config1', 'config2');
|
||||
|
|
||||
| NOTE: This item is intended for use ONLY if you have created custom
|
||||
| config files. Otherwise, leave it blank.
|
||||
|
|
||||
*/
|
||||
$autoload['config'] = array();
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| Auto-load Language files
|
||||
| -------------------------------------------------------------------
|
||||
| Prototype:
|
||||
|
|
||||
| $autoload['language'] = array('lang1', 'lang2');
|
||||
|
|
||||
| NOTE: Do not include the "_lang" part of your file. For example
|
||||
| "codeigniter_lang.php" would be referenced as array('codeigniter');
|
||||
|
|
||||
*/
|
||||
$autoload['language'] = array();
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| Auto-load Models
|
||||
| -------------------------------------------------------------------
|
||||
| Prototype:
|
||||
|
|
||||
| $autoload['model'] = array('first_model', 'second_model');
|
||||
|
|
||||
| You can also supply an alternative model name to be assigned
|
||||
| in the controller:
|
||||
|
|
||||
| $autoload['model'] = array('first_model' => 'first');
|
||||
*/
|
||||
$autoload['model'] = array();
|
||||
@@ -0,0 +1,533 @@
|
||||
<?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/keuangan/';
|
||||
$config['base_url'] = 'https://accounting.radiq.my.id/';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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'] = '';
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Display Debug backtrace
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If set to TRUE, a backtrace will be displayed along with php errors. If
|
||||
| error_reporting is disabled, the backtrace will not display, regardless
|
||||
| of this setting
|
||||
|
|
||||
*/
|
||||
defined('SHOW_DEBUG_BACKTRACE') OR define('SHOW_DEBUG_BACKTRACE', TRUE);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| File and Directory Modes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These prefs are used when checking and setting modes when working
|
||||
| with the file system. The defaults are fine on servers with proper
|
||||
| security, but you may wish (or even need) to change the values in
|
||||
| certain environments (Apache running a separate process for each
|
||||
| user, PHP under CGI with Apache suEXEC, etc.). Octal values should
|
||||
| always be used to set the mode correctly.
|
||||
|
|
||||
*/
|
||||
defined('FILE_READ_MODE') OR define('FILE_READ_MODE', 0644);
|
||||
defined('FILE_WRITE_MODE') OR define('FILE_WRITE_MODE', 0666);
|
||||
defined('DIR_READ_MODE') OR define('DIR_READ_MODE', 0755);
|
||||
defined('DIR_WRITE_MODE') OR define('DIR_WRITE_MODE', 0755);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| File Stream Modes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These modes are used when working with fopen()/popen()
|
||||
|
|
||||
*/
|
||||
defined('FOPEN_READ') OR define('FOPEN_READ', 'rb');
|
||||
defined('FOPEN_READ_WRITE') OR define('FOPEN_READ_WRITE', 'r+b');
|
||||
defined('FOPEN_WRITE_CREATE_DESTRUCTIVE') OR define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb'); // truncates existing file data, use with care
|
||||
defined('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE') OR define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE', 'w+b'); // truncates existing file data, use with care
|
||||
defined('FOPEN_WRITE_CREATE') OR define('FOPEN_WRITE_CREATE', 'ab');
|
||||
defined('FOPEN_READ_WRITE_CREATE') OR define('FOPEN_READ_WRITE_CREATE', 'a+b');
|
||||
defined('FOPEN_WRITE_CREATE_STRICT') OR define('FOPEN_WRITE_CREATE_STRICT', 'xb');
|
||||
defined('FOPEN_READ_WRITE_CREATE_STRICT') OR define('FOPEN_READ_WRITE_CREATE_STRICT', 'x+b');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Exit Status Codes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Used to indicate the conditions under which the script is exit()ing.
|
||||
| While there is no universal standard for error codes, there are some
|
||||
| broad conventions. Three such conventions are mentioned below, for
|
||||
| those who wish to make use of them. The CodeIgniter defaults were
|
||||
| chosen for the least overlap with these conventions, while still
|
||||
| leaving room for others to be defined in future versions and user
|
||||
| applications.
|
||||
|
|
||||
| The three main conventions used for determining exit status codes
|
||||
| are as follows:
|
||||
|
|
||||
| Standard C/C++ Library (stdlibc):
|
||||
| http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
|
||||
| (This link also contains other GNU-specific conventions)
|
||||
| BSD sysexits.h:
|
||||
| http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
|
||||
| Bash scripting:
|
||||
| http://tldp.org/LDP/abs/html/exitcodes.html
|
||||
|
|
||||
*/
|
||||
defined('EXIT_SUCCESS') OR define('EXIT_SUCCESS', 0); // no errors
|
||||
defined('EXIT_ERROR') OR define('EXIT_ERROR', 1); // generic error
|
||||
defined('EXIT_CONFIG') OR define('EXIT_CONFIG', 3); // configuration error
|
||||
defined('EXIT_UNKNOWN_FILE') OR define('EXIT_UNKNOWN_FILE', 4); // file not found
|
||||
defined('EXIT_UNKNOWN_CLASS') OR define('EXIT_UNKNOWN_CLASS', 5); // unknown class
|
||||
defined('EXIT_UNKNOWN_METHOD') OR define('EXIT_UNKNOWN_METHOD', 6); // unknown class member
|
||||
defined('EXIT_USER_INPUT') OR define('EXIT_USER_INPUT', 7); // invalid user input
|
||||
defined('EXIT_DATABASE') OR define('EXIT_DATABASE', 8); // database error
|
||||
defined('EXIT__AUTO_MIN') OR define('EXIT__AUTO_MIN', 9); // lowest automatically-assigned error code
|
||||
defined('EXIT__AUTO_MAX') OR define('EXIT__AUTO_MAX', 125); // highest automatically-assigned error code
|
||||
@@ -0,0 +1,98 @@
|
||||
<?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' => 3309, // port PostgreSQL
|
||||
'username' => 'keuangan',
|
||||
'password' => '@P4ssw0rd',
|
||||
'database' => 'keuangan',
|
||||
'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,24 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
$_doctypes = array(
|
||||
'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
|
||||
'xhtml1-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
|
||||
'xhtml1-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
|
||||
'xhtml1-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
|
||||
'xhtml-basic11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
|
||||
'html5' => '<!DOCTYPE html>',
|
||||
'html4-strict' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
|
||||
'html4-trans' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
|
||||
'html4-frame' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
|
||||
'mathml1' => '<!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">',
|
||||
'mathml2' => '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">',
|
||||
'svg10' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">',
|
||||
'svg11' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
|
||||
'svg11-basic' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">',
|
||||
'svg11-tiny' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">',
|
||||
'xhtml-math-svg-xh' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
|
||||
'xhtml-math-svg-sh' => '<!DOCTYPE svg:svg PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
|
||||
'xhtml-rdfa-1' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">',
|
||||
'xhtml-rdfa-2' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.1//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd">'
|
||||
);
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| Foreign Characters
|
||||
| -------------------------------------------------------------------
|
||||
| This file contains an array of foreign characters for transliteration
|
||||
| conversion used by the Text helper
|
||||
|
|
||||
*/
|
||||
$foreign_characters = array(
|
||||
'/ä|æ|ǽ/' => 'ae',
|
||||
'/ö|œ/' => 'oe',
|
||||
'/ü/' => 'ue',
|
||||
'/Ä/' => 'Ae',
|
||||
'/Ü/' => 'Ue',
|
||||
'/Ö/' => 'Oe',
|
||||
'/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|Α|Ά|Ả|Ạ|Ầ|Ẫ|Ẩ|Ậ|Ằ|Ắ|Ẵ|Ẳ|Ặ|А/' => 'A',
|
||||
'/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª|α|ά|ả|ạ|ầ|ấ|ẫ|ẩ|ậ|ằ|ắ|ẵ|ẳ|ặ|а/' => 'a',
|
||||
'/Б/' => 'B',
|
||||
'/б/' => 'b',
|
||||
'/Ç|Ć|Ĉ|Ċ|Č/' => 'C',
|
||||
'/ç|ć|ĉ|ċ|č/' => 'c',
|
||||
'/Д|Δ/' => 'D',
|
||||
'/д|δ/' => 'd',
|
||||
'/Ð|Ď|Đ/' => 'Dj',
|
||||
'/ð|ď|đ/' => 'dj',
|
||||
'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ|Ẽ|Ẻ|Ẹ|Ề|Ế|Ễ|Ể|Ệ|Е|Э/' => 'E',
|
||||
'/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε|ẽ|ẻ|ẹ|ề|ế|ễ|ể|ệ|е|э/' => 'e',
|
||||
'/Ф/' => 'F',
|
||||
'/ф/' => 'f',
|
||||
'/Ĝ|Ğ|Ġ|Ģ|Γ|Г|Ґ/' => 'G',
|
||||
'/ĝ|ğ|ġ|ģ|γ|г|ґ/' => 'g',
|
||||
'/Ĥ|Ħ/' => 'H',
|
||||
'/ĥ|ħ/' => 'h',
|
||||
'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ|Ỉ|Ị|И|Ы/' => 'I',
|
||||
'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ|ỉ|ị|и|ы|ї/' => 'i',
|
||||
'/Ĵ/' => 'J',
|
||||
'/ĵ/' => 'j',
|
||||
'/Θ/' => 'TH',
|
||||
'/θ/' => 'th',
|
||||
'/Ķ|Κ|К/' => 'K',
|
||||
'/ķ|κ|к/' => 'k',
|
||||
'/Ĺ|Ļ|Ľ|Ŀ|Ł|Λ|Л/' => 'L',
|
||||
'/ĺ|ļ|ľ|ŀ|ł|λ|л/' => 'l',
|
||||
'/М/' => 'M',
|
||||
'/м/' => 'm',
|
||||
'/Ñ|Ń|Ņ|Ň|Ν|Н/' => 'N',
|
||||
'/ñ|ń|ņ|ň|ʼn|ν|н/' => 'n',
|
||||
'/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|Ο|Ό|Ω|Ώ|Ỏ|Ọ|Ồ|Ố|Ỗ|Ổ|Ộ|Ờ|Ớ|Ỡ|Ở|Ợ|О/' => 'O',
|
||||
'/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|ο|ό|ω|ώ|ỏ|ọ|ồ|ố|ỗ|ổ|ộ|ờ|ớ|ỡ|ở|ợ|о/' => 'o',
|
||||
'/П/' => 'P',
|
||||
'/п/' => 'p',
|
||||
'/Ŕ|Ŗ|Ř|Ρ|Р/' => 'R',
|
||||
'/ŕ|ŗ|ř|ρ|р/' => 'r',
|
||||
'/Ś|Ŝ|Ş|Ș|Š|Σ|С/' => 'S',
|
||||
'/ś|ŝ|ş|ș|š|ſ|σ|ς|с/' => 's',
|
||||
'/Ț|Ţ|Ť|Ŧ|Τ|Т/' => 'T',
|
||||
'/ț|ţ|ť|ŧ|τ|т/' => 't',
|
||||
'/Þ|þ/' => 'th',
|
||||
'/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|Ũ|Ủ|Ụ|Ừ|Ứ|Ữ|Ử|Ự|У/' => 'U',
|
||||
'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ|ủ|ụ|ừ|ứ|ữ|ử|ự|у/' => 'u',
|
||||
'/Ƴ|Ɏ|Ỵ|Ẏ|Ӳ|Ӯ|Ў|Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ|Ỳ|Ỹ|Ỷ|Ỵ|Й/' => 'Y',
|
||||
'/ẙ|ʏ|ƴ|ɏ|ỵ|ẏ|ӳ|ӯ|ў|ý|ÿ|ŷ|ỳ|ỹ|ỷ|ỵ|й/' => 'y',
|
||||
'/В/' => 'V',
|
||||
'/в/' => 'v',
|
||||
'/Ŵ/' => 'W',
|
||||
'/ŵ/' => 'w',
|
||||
'/Φ/' => 'F',
|
||||
'/φ/' => 'f',
|
||||
'/Χ/' => 'CH',
|
||||
'/χ/' => 'ch',
|
||||
'/Ź|Ż|Ž|Ζ|З/' => 'Z',
|
||||
'/ź|ż|ž|ζ|з/' => 'z',
|
||||
'/Æ|Ǽ/' => 'AE',
|
||||
'/ß/' => 'ss',
|
||||
'/IJ/' => 'IJ',
|
||||
'/ij/' => 'ij',
|
||||
'/Œ/' => 'OE',
|
||||
'/ƒ/' => 'f',
|
||||
'/Ξ/' => 'KS',
|
||||
'/ξ/' => 'ks',
|
||||
'/Π/' => 'P',
|
||||
'/π/' => 'p',
|
||||
'/Β/' => 'V',
|
||||
'/β/' => 'v',
|
||||
'/Μ/' => 'M',
|
||||
'/μ/' => 'm',
|
||||
'/Ψ/' => 'PS',
|
||||
'/ψ/' => 'ps',
|
||||
'/Ё/' => 'Yo',
|
||||
'/ё/' => 'yo',
|
||||
'/Є/' => 'Ye',
|
||||
'/є/' => 'ye',
|
||||
'/Ї/' => 'Yi',
|
||||
'/Ж/' => 'Zh',
|
||||
'/ж/' => 'zh',
|
||||
'/Х/' => 'Kh',
|
||||
'/х/' => 'kh',
|
||||
'/Ц/' => 'Ts',
|
||||
'/ц/' => 'ts',
|
||||
'/Ч/' => 'Ch',
|
||||
'/ч/' => 'ch',
|
||||
'/Ш/' => 'Sh',
|
||||
'/ш/' => 'sh',
|
||||
'/Щ/' => 'Shch',
|
||||
'/щ/' => 'shch',
|
||||
'/Ъ|ъ|Ь|ь/' => '',
|
||||
'/Ю/' => 'Yu',
|
||||
'/ю/' => 'yu',
|
||||
'/Я/' => 'Ya',
|
||||
'/я/' => 'ya'
|
||||
);
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------------
|
||||
| Hooks
|
||||
| -------------------------------------------------------------------------
|
||||
| This file lets you define "hooks" to extend CI without hacking the core
|
||||
| files. Please see the user guide for info:
|
||||
|
|
||||
| https://codeigniter.com/userguide3/general/hooks.html
|
||||
|
|
||||
*/
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------------
|
||||
| Memcached settings
|
||||
| -------------------------------------------------------------------------
|
||||
| Your Memcached servers can be specified below.
|
||||
|
|
||||
| See: https://codeigniter.com/userguide3/libraries/caching.html#memcached
|
||||
|
|
||||
*/
|
||||
$config = array(
|
||||
'default' => array(
|
||||
'hostname' => '127.0.0.1',
|
||||
'port' => '11211',
|
||||
'weight' => '1',
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enable/Disable Migrations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Migrations are disabled by default for security reasons.
|
||||
| You should enable migrations whenever you intend to do a schema migration
|
||||
| and disable it back when you're done.
|
||||
|
|
||||
*/
|
||||
$config['migration_enabled'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Migration Type
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Migration file names may be based on a sequential identifier or on
|
||||
| a timestamp. Options are:
|
||||
|
|
||||
| 'sequential' = Sequential migration naming (001_add_blog.php)
|
||||
| 'timestamp' = Timestamp migration naming (20121031104401_add_blog.php)
|
||||
| Use timestamp format YYYYMMDDHHIISS.
|
||||
|
|
||||
| Note: If this configuration value is missing the Migration library
|
||||
| defaults to 'sequential' for backward compatibility with CI2.
|
||||
|
|
||||
*/
|
||||
$config['migration_type'] = 'timestamp';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Migrations table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the name of the table that will store the current migrations state.
|
||||
| When migrations runs it will store in a database table which migration
|
||||
| level the system is at. It then compares the migration level in this
|
||||
| table to the $config['migration_version'] if they are not the same it
|
||||
| will migrate up. This must be set.
|
||||
|
|
||||
*/
|
||||
$config['migration_table'] = 'migrations';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Auto Migrate To Latest
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If this is set to TRUE when you load the migrations class and have
|
||||
| $config['migration_enabled'] set to TRUE the system will auto migrate
|
||||
| to your latest migration (whatever $config['migration_version'] is
|
||||
| set to). This way you do not have to call migrations anywhere else
|
||||
| in your code to have the latest migration.
|
||||
|
|
||||
*/
|
||||
$config['migration_auto_latest'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Migrations version
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is used to set migration version that the file system should be on.
|
||||
| If you run $this->migration->current() this is the version that schema will
|
||||
| be upgraded / downgraded to.
|
||||
|
|
||||
*/
|
||||
$config['migration_version'] = 0;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Migrations Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Path to your migrations folder.
|
||||
| Typically, it will be within your application path.
|
||||
| Also, writing permission is required within the migrations path.
|
||||
|
|
||||
*/
|
||||
$config['migration_path'] = APPPATH.'migrations/';
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| MIME TYPES
|
||||
| -------------------------------------------------------------------
|
||||
| This file contains an array of mime types. It is used by the
|
||||
| Upload class to help identify allowed file types.
|
||||
|
|
||||
*/
|
||||
return array(
|
||||
'hqx' => array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-mac-binhex40'),
|
||||
'cpt' => 'application/mac-compactpro',
|
||||
'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel', 'text/plain'),
|
||||
'bin' => array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-macbinary'),
|
||||
'dms' => 'application/octet-stream',
|
||||
'lha' => 'application/octet-stream',
|
||||
'lzh' => 'application/octet-stream',
|
||||
'exe' => array('application/octet-stream', 'application/x-msdownload'),
|
||||
'class' => 'application/octet-stream',
|
||||
'psd' => array('application/x-photoshop', 'image/vnd.adobe.photoshop'),
|
||||
'so' => 'application/octet-stream',
|
||||
'sea' => 'application/octet-stream',
|
||||
'dll' => 'application/octet-stream',
|
||||
'oda' => 'application/oda',
|
||||
'pdf' => array('application/pdf', 'application/force-download', 'application/x-download', 'binary/octet-stream'),
|
||||
'ai' => array('application/pdf', 'application/postscript'),
|
||||
'eps' => 'application/postscript',
|
||||
'ps' => 'application/postscript',
|
||||
'smi' => 'application/smil',
|
||||
'smil' => 'application/smil',
|
||||
'mif' => 'application/vnd.mif',
|
||||
'xls' => array('application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'application/x-ms-excel', 'application/x-excel', 'application/x-dos_ms_excel', 'application/xls', 'application/x-xls', 'application/excel', 'application/download', 'application/vnd.ms-office', 'application/msword'),
|
||||
'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint', 'application/vnd.ms-office', 'application/msword'),
|
||||
'pptx' => array('application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/x-zip', 'application/zip'),
|
||||
'wbxml' => 'application/wbxml',
|
||||
'wmlc' => 'application/wmlc',
|
||||
'dcr' => 'application/x-director',
|
||||
'dir' => 'application/x-director',
|
||||
'dxr' => 'application/x-director',
|
||||
'dvi' => 'application/x-dvi',
|
||||
'gtar' => 'application/x-gtar',
|
||||
'gz' => 'application/x-gzip',
|
||||
'gzip' => 'application/x-gzip',
|
||||
'php' => array('application/x-httpd-php', 'application/php', 'application/x-php', 'text/php', 'text/x-php', 'application/x-httpd-php-source'),
|
||||
'php4' => 'application/x-httpd-php',
|
||||
'php3' => 'application/x-httpd-php',
|
||||
'phtml' => 'application/x-httpd-php',
|
||||
'phps' => 'application/x-httpd-php-source',
|
||||
'js' => array('application/x-javascript', 'text/plain'),
|
||||
'swf' => 'application/x-shockwave-flash',
|
||||
'sit' => 'application/x-stuffit',
|
||||
'tar' => 'application/x-tar',
|
||||
'tgz' => array('application/x-tar', 'application/x-gzip-compressed'),
|
||||
'z' => 'application/x-compress',
|
||||
'xhtml' => 'application/xhtml+xml',
|
||||
'xht' => 'application/xhtml+xml',
|
||||
'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed', 'application/s-compressed', 'multipart/x-zip'),
|
||||
'rar' => array('application/x-rar', 'application/rar', 'application/x-rar-compressed'),
|
||||
'mid' => 'audio/midi',
|
||||
'midi' => 'audio/midi',
|
||||
'mpga' => 'audio/mpeg',
|
||||
'mp2' => 'audio/mpeg',
|
||||
'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
|
||||
'aif' => array('audio/x-aiff', 'audio/aiff'),
|
||||
'aiff' => array('audio/x-aiff', 'audio/aiff'),
|
||||
'aifc' => 'audio/x-aiff',
|
||||
'ram' => 'audio/x-pn-realaudio',
|
||||
'rm' => 'audio/x-pn-realaudio',
|
||||
'rpm' => 'audio/x-pn-realaudio-plugin',
|
||||
'ra' => 'audio/x-realaudio',
|
||||
'rv' => 'video/vnd.rn-realvideo',
|
||||
'wav' => array('audio/x-wav', 'audio/wave', 'audio/wav'),
|
||||
'bmp' => array('image/bmp', 'image/x-bmp', 'image/x-bitmap', 'image/x-xbitmap', 'image/x-win-bitmap', 'image/x-windows-bmp', 'image/ms-bmp', 'image/x-ms-bmp', 'application/bmp', 'application/x-bmp', 'application/x-win-bitmap'),
|
||||
'gif' => 'image/gif',
|
||||
'jpeg' => array('image/jpeg', 'image/pjpeg'),
|
||||
'jpg' => array('image/jpeg', 'image/pjpeg'),
|
||||
'jpe' => array('image/jpeg', 'image/pjpeg'),
|
||||
'jp2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
|
||||
'j2k' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
|
||||
'jpf' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
|
||||
'jpg2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
|
||||
'jpx' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
|
||||
'jpm' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
|
||||
'mj2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
|
||||
'mjp2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
|
||||
'png' => array('image/png', 'image/x-png'),
|
||||
'tiff' => 'image/tiff',
|
||||
'tif' => 'image/tiff',
|
||||
'heic' => 'image/heic',
|
||||
'heif' => 'image/heif',
|
||||
'css' => array('text/css', 'text/plain'),
|
||||
'html' => array('text/html', 'text/plain'),
|
||||
'htm' => array('text/html', 'text/plain'),
|
||||
'shtml' => array('text/html', 'text/plain'),
|
||||
'txt' => 'text/plain',
|
||||
'text' => 'text/plain',
|
||||
'log' => array('text/plain', 'text/x-log'),
|
||||
'rtx' => 'text/richtext',
|
||||
'rtf' => 'text/rtf',
|
||||
'xml' => array('application/xml', 'text/xml', 'text/plain'),
|
||||
'xsl' => array('application/xml', 'text/xsl', 'text/xml'),
|
||||
'mpeg' => 'video/mpeg',
|
||||
'mpg' => 'video/mpeg',
|
||||
'mpe' => 'video/mpeg',
|
||||
'qt' => 'video/quicktime',
|
||||
'mov' => 'video/quicktime',
|
||||
'avi' => array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
|
||||
'movie' => 'video/x-sgi-movie',
|
||||
'doc' => array('application/msword', 'application/vnd.ms-office'),
|
||||
'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword', 'application/x-zip'),
|
||||
'dot' => array('application/msword', 'application/vnd.ms-office'),
|
||||
'dotx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'),
|
||||
'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip', 'application/vnd.ms-excel', 'application/msword', 'application/x-zip'),
|
||||
'word' => array('application/msword', 'application/octet-stream'),
|
||||
'xl' => 'application/excel',
|
||||
'eml' => 'message/rfc822',
|
||||
'json' => array('application/json', 'text/json'),
|
||||
'pem' => array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'),
|
||||
'p10' => array('application/x-pkcs10', 'application/pkcs10'),
|
||||
'p12' => 'application/x-pkcs12',
|
||||
'p7a' => 'application/x-pkcs7-signature',
|
||||
'p7c' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
|
||||
'p7m' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'),
|
||||
'p7r' => 'application/x-pkcs7-certreqresp',
|
||||
'p7s' => 'application/pkcs7-signature',
|
||||
'crt' => array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'),
|
||||
'crl' => array('application/pkix-crl', 'application/pkcs-crl'),
|
||||
'der' => 'application/x-x509-ca-cert',
|
||||
'kdb' => 'application/octet-stream',
|
||||
'pgp' => 'application/pgp',
|
||||
'gpg' => 'application/gpg-keys',
|
||||
'sst' => 'application/octet-stream',
|
||||
'csr' => 'application/octet-stream',
|
||||
'rsa' => 'application/x-pkcs7',
|
||||
'cer' => array('application/pkix-cert', 'application/x-x509-ca-cert'),
|
||||
'3g2' => 'video/3gpp2',
|
||||
'3gp' => array('video/3gp', 'video/3gpp'),
|
||||
'mp4' => 'video/mp4',
|
||||
'm4a' => 'audio/x-m4a',
|
||||
'f4v' => array('video/mp4', 'video/x-f4v'),
|
||||
'flv' => 'video/x-flv',
|
||||
'webm' => 'video/webm',
|
||||
'aac' => array('audio/x-aac', 'audio/aac'),
|
||||
'm4u' => 'application/vnd.mpegurl',
|
||||
'm3u' => 'text/plain',
|
||||
'xspf' => 'application/xspf+xml',
|
||||
'vlc' => 'application/videolan',
|
||||
'wmv' => array('video/x-ms-wmv', 'video/x-ms-asf'),
|
||||
'au' => 'audio/x-au',
|
||||
'ac3' => 'audio/ac3',
|
||||
'flac' => 'audio/x-flac',
|
||||
'ogg' => array('audio/ogg', 'video/ogg', 'application/ogg'),
|
||||
'kmz' => array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'),
|
||||
'kml' => array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'),
|
||||
'ics' => 'text/calendar',
|
||||
'ical' => 'text/calendar',
|
||||
'zsh' => 'text/x-scriptzsh',
|
||||
'7z' => array('application/x-7z-compressed', 'application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'),
|
||||
'7zip' => array('application/x-7z-compressed', 'application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'),
|
||||
'cdr' => array('application/cdr', 'application/coreldraw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'),
|
||||
'wma' => array('audio/x-ms-wma', 'video/x-ms-asf'),
|
||||
'jar' => array('application/java-archive', 'application/x-java-application', 'application/x-jar', 'application/x-compressed'),
|
||||
'svg' => array('image/svg+xml', 'image/svg', 'application/xml', 'text/xml'),
|
||||
'vcf' => 'text/x-vcard',
|
||||
'srt' => array('text/srt', 'text/plain'),
|
||||
'vtt' => array('text/vtt', 'text/plain'),
|
||||
'ico' => array('image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon'),
|
||||
'odc' => 'application/vnd.oasis.opendocument.chart',
|
||||
'otc' => 'application/vnd.oasis.opendocument.chart-template',
|
||||
'odf' => 'application/vnd.oasis.opendocument.formula',
|
||||
'otf' => 'application/vnd.oasis.opendocument.formula-template',
|
||||
'odg' => 'application/vnd.oasis.opendocument.graphics',
|
||||
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
|
||||
'odi' => 'application/vnd.oasis.opendocument.image',
|
||||
'oti' => 'application/vnd.oasis.opendocument.image-template',
|
||||
'odp' => 'application/vnd.oasis.opendocument.presentation',
|
||||
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
|
||||
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
|
||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||
'odm' => 'application/vnd.oasis.opendocument.text-master',
|
||||
'ott' => 'application/vnd.oasis.opendocument.text-template',
|
||||
'oth' => 'application/vnd.oasis.opendocument.text-web'
|
||||
);
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------------
|
||||
| Profiler Sections
|
||||
| -------------------------------------------------------------------------
|
||||
| This file lets you determine whether or not various sections of Profiler
|
||||
| data are displayed when the Profiler is enabled.
|
||||
| Please see the user guide for info:
|
||||
|
|
||||
| https://codeigniter.com/userguide3/general/profiling.html
|
||||
|
|
||||
*/
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------------
|
||||
| URI ROUTING
|
||||
| -------------------------------------------------------------------------
|
||||
| This file lets you re-map URI requests to specific controller functions.
|
||||
|
|
||||
| Typically there is a one-to-one relationship between a URL string
|
||||
| and its corresponding controller class/method. The segments in a
|
||||
| URL normally follow this pattern:
|
||||
|
|
||||
| example.com/class/method/id/
|
||||
|
|
||||
| In some instances, however, you may want to remap this relationship
|
||||
| so that a different class/function is called than the one
|
||||
| corresponding to the URL.
|
||||
|
|
||||
| Please see the user guide for complete details:
|
||||
|
|
||||
| https://codeigniter.com/userguide3/general/routing.html
|
||||
|
|
||||
| -------------------------------------------------------------------------
|
||||
| RESERVED ROUTES
|
||||
| -------------------------------------------------------------------------
|
||||
|
|
||||
| There are three reserved routes:
|
||||
|
|
||||
| $route['default_controller'] = 'welcome';
|
||||
|
|
||||
| This route indicates which controller class should be loaded if the
|
||||
| URI contains no data. In the above example, the "welcome" class
|
||||
| would be loaded.
|
||||
|
|
||||
| $route['404_override'] = 'errors/page_missing';
|
||||
|
|
||||
| This route will tell the Router which controller/method to use if those
|
||||
| provided in the URL cannot be matched to a valid route.
|
||||
|
|
||||
| $route['translate_uri_dashes'] = FALSE;
|
||||
|
|
||||
| This is not exactly a route, but allows you to automatically route
|
||||
| controller and method names that contain dashes. '-' isn't a valid
|
||||
| class or method name character, so it requires translation.
|
||||
| When you set this option to TRUE, it will replace ALL dashes in the
|
||||
| controller and method URI segments.
|
||||
|
|
||||
| Examples: my-controller/index -> my_controller/index
|
||||
| my-controller/my-method -> my_controller/my_method
|
||||
*/
|
||||
$route['default_controller'] = 'dashboard';
|
||||
$route['404_override'] = '';
|
||||
$route['translate_uri_dashes'] = FALSE;
|
||||
|
||||
// untuk webhook absensi
|
||||
$route['iclock/cdata'] = 'AttendanceWebhook/cdata';
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| SMILEYS
|
||||
| -------------------------------------------------------------------
|
||||
| This file contains an array of smileys for use with the emoticon helper.
|
||||
| Individual images can be used to replace multiple smileys. For example:
|
||||
| :-) and :) use the same image replacement.
|
||||
|
|
||||
| Please see user guide for more info:
|
||||
| https://codeigniter.com/userguide3/helpers/smiley_helper.html
|
||||
|
|
||||
*/
|
||||
$smileys = array(
|
||||
|
||||
// smiley image name width height alt
|
||||
|
||||
':-)' => array('grin.gif', '19', '19', 'grin'),
|
||||
':lol:' => array('lol.gif', '19', '19', 'LOL'),
|
||||
':cheese:' => array('cheese.gif', '19', '19', 'cheese'),
|
||||
':)' => array('smile.gif', '19', '19', 'smile'),
|
||||
';-)' => array('wink.gif', '19', '19', 'wink'),
|
||||
';)' => array('wink.gif', '19', '19', 'wink'),
|
||||
':smirk:' => array('smirk.gif', '19', '19', 'smirk'),
|
||||
':roll:' => array('rolleyes.gif', '19', '19', 'rolleyes'),
|
||||
':-S' => array('confused.gif', '19', '19', 'confused'),
|
||||
':wow:' => array('surprise.gif', '19', '19', 'surprised'),
|
||||
':bug:' => array('bigsurprise.gif', '19', '19', 'big surprise'),
|
||||
':-P' => array('tongue_laugh.gif', '19', '19', 'tongue laugh'),
|
||||
'%-P' => array('tongue_rolleye.gif', '19', '19', 'tongue rolleye'),
|
||||
';-P' => array('tongue_wink.gif', '19', '19', 'tongue wink'),
|
||||
':P' => array('raspberry.gif', '19', '19', 'raspberry'),
|
||||
':blank:' => array('blank.gif', '19', '19', 'blank stare'),
|
||||
':long:' => array('longface.gif', '19', '19', 'long face'),
|
||||
':ohh:' => array('ohh.gif', '19', '19', 'ohh'),
|
||||
':grrr:' => array('grrr.gif', '19', '19', 'grrr'),
|
||||
':gulp:' => array('gulp.gif', '19', '19', 'gulp'),
|
||||
'8-/' => array('ohoh.gif', '19', '19', 'oh oh'),
|
||||
':down:' => array('downer.gif', '19', '19', 'downer'),
|
||||
':red:' => array('embarrassed.gif', '19', '19', 'red face'),
|
||||
':sick:' => array('sick.gif', '19', '19', 'sick'),
|
||||
':shut:' => array('shuteye.gif', '19', '19', 'shut eye'),
|
||||
':-/' => array('hmm.gif', '19', '19', 'hmmm'),
|
||||
'>:(' => array('mad.gif', '19', '19', 'mad'),
|
||||
':mad:' => array('mad.gif', '19', '19', 'mad'),
|
||||
'>:-(' => array('angry.gif', '19', '19', 'angry'),
|
||||
':angry:' => array('angry.gif', '19', '19', 'angry'),
|
||||
':zip:' => array('zip.gif', '19', '19', 'zipper'),
|
||||
':kiss:' => array('kiss.gif', '19', '19', 'kiss'),
|
||||
':ahhh:' => array('shock.gif', '19', '19', 'shock'),
|
||||
':coolsmile:' => array('shade_smile.gif', '19', '19', 'cool smile'),
|
||||
':coolsmirk:' => array('shade_smirk.gif', '19', '19', 'cool smirk'),
|
||||
':coolgrin:' => array('shade_grin.gif', '19', '19', 'cool grin'),
|
||||
':coolhmm:' => array('shade_hmm.gif', '19', '19', 'cool hmm'),
|
||||
':coolmad:' => array('shade_mad.gif', '19', '19', 'cool mad'),
|
||||
':coolcheese:' => array('shade_cheese.gif', '19', '19', 'cool cheese'),
|
||||
':vampire:' => array('vampire.gif', '19', '19', 'vampire'),
|
||||
':snake:' => array('snake.gif', '19', '19', 'snake'),
|
||||
':exclaim:' => array('exclaim.gif', '19', '19', 'exclaim'),
|
||||
':question:' => array('question.gif', '19', '19', 'question')
|
||||
|
||||
);
|
||||
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| USER AGENT TYPES
|
||||
| -------------------------------------------------------------------
|
||||
| This file contains four arrays of user agent data. It is used by the
|
||||
| User Agent Class to help identify browser, platform, robot, and
|
||||
| mobile device data. The array keys are used to identify the device
|
||||
| and the array values are used to set the actual name of the item.
|
||||
*/
|
||||
$platforms = array(
|
||||
'windows nt 10.0' => 'Windows 10',
|
||||
'windows nt 6.3' => 'Windows 8.1',
|
||||
'windows nt 6.2' => 'Windows 8',
|
||||
'windows nt 6.1' => 'Windows 7',
|
||||
'windows nt 6.0' => 'Windows Vista',
|
||||
'windows nt 5.2' => 'Windows 2003',
|
||||
'windows nt 5.1' => 'Windows XP',
|
||||
'windows nt 5.0' => 'Windows 2000',
|
||||
'windows nt 4.0' => 'Windows NT 4.0',
|
||||
'winnt4.0' => 'Windows NT 4.0',
|
||||
'winnt 4.0' => 'Windows NT',
|
||||
'winnt' => 'Windows NT',
|
||||
'windows 98' => 'Windows 98',
|
||||
'win98' => 'Windows 98',
|
||||
'windows 95' => 'Windows 95',
|
||||
'win95' => 'Windows 95',
|
||||
'windows phone' => 'Windows Phone',
|
||||
'windows' => 'Unknown Windows OS',
|
||||
'android' => 'Android',
|
||||
'blackberry' => 'BlackBerry',
|
||||
'iphone' => 'iOS',
|
||||
'ipad' => 'iOS',
|
||||
'ipod' => 'iOS',
|
||||
'os x' => 'Mac OS X',
|
||||
'ppc mac' => 'Power PC Mac',
|
||||
'freebsd' => 'FreeBSD',
|
||||
'ppc' => 'Macintosh',
|
||||
'linux' => 'Linux',
|
||||
'debian' => 'Debian',
|
||||
'sunos' => 'Sun Solaris',
|
||||
'beos' => 'BeOS',
|
||||
'apachebench' => 'ApacheBench',
|
||||
'aix' => 'AIX',
|
||||
'irix' => 'Irix',
|
||||
'osf' => 'DEC OSF',
|
||||
'hp-ux' => 'HP-UX',
|
||||
'netbsd' => 'NetBSD',
|
||||
'bsdi' => 'BSDi',
|
||||
'openbsd' => 'OpenBSD',
|
||||
'gnu' => 'GNU/Linux',
|
||||
'unix' => 'Unknown Unix OS',
|
||||
'symbian' => 'Symbian OS'
|
||||
);
|
||||
|
||||
|
||||
// The order of this array should NOT be changed. Many browsers return
|
||||
// multiple browser types so we want to identify the sub-type first.
|
||||
$browsers = array(
|
||||
'OPR' => 'Opera',
|
||||
'Flock' => 'Flock',
|
||||
'Edge' => 'Edge',
|
||||
'Chrome' => 'Chrome',
|
||||
// Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
|
||||
'Opera.*?Version' => 'Opera',
|
||||
'Opera' => 'Opera',
|
||||
'MSIE' => 'Internet Explorer',
|
||||
'Internet Explorer' => 'Internet Explorer',
|
||||
'Trident.* rv' => 'Internet Explorer',
|
||||
'Shiira' => 'Shiira',
|
||||
'Firefox' => 'Firefox',
|
||||
'Chimera' => 'Chimera',
|
||||
'Phoenix' => 'Phoenix',
|
||||
'Firebird' => 'Firebird',
|
||||
'Camino' => 'Camino',
|
||||
'Netscape' => 'Netscape',
|
||||
'OmniWeb' => 'OmniWeb',
|
||||
'Safari' => 'Safari',
|
||||
'Mozilla' => 'Mozilla',
|
||||
'Konqueror' => 'Konqueror',
|
||||
'icab' => 'iCab',
|
||||
'Lynx' => 'Lynx',
|
||||
'Links' => 'Links',
|
||||
'hotjava' => 'HotJava',
|
||||
'amaya' => 'Amaya',
|
||||
'IBrowse' => 'IBrowse',
|
||||
'Maxthon' => 'Maxthon',
|
||||
'Ubuntu' => 'Ubuntu Web Browser'
|
||||
);
|
||||
|
||||
$mobiles = array(
|
||||
// legacy array, old values commented out
|
||||
'mobileexplorer' => 'Mobile Explorer',
|
||||
// 'openwave' => 'Open Wave',
|
||||
// 'opera mini' => 'Opera Mini',
|
||||
// 'operamini' => 'Opera Mini',
|
||||
// 'elaine' => 'Palm',
|
||||
'palmsource' => 'Palm',
|
||||
// 'digital paths' => 'Palm',
|
||||
// 'avantgo' => 'Avantgo',
|
||||
// 'xiino' => 'Xiino',
|
||||
'palmscape' => 'Palmscape',
|
||||
// 'nokia' => 'Nokia',
|
||||
// 'ericsson' => 'Ericsson',
|
||||
// 'blackberry' => 'BlackBerry',
|
||||
// 'motorola' => 'Motorola'
|
||||
|
||||
// Phones and Manufacturers
|
||||
'motorola' => 'Motorola',
|
||||
'nokia' => 'Nokia',
|
||||
'nexus' => 'Nexus',
|
||||
'palm' => 'Palm',
|
||||
'iphone' => 'Apple iPhone',
|
||||
'ipad' => 'iPad',
|
||||
'ipod' => 'Apple iPod Touch',
|
||||
'sony' => 'Sony Ericsson',
|
||||
'ericsson' => 'Sony Ericsson',
|
||||
'blackberry' => 'BlackBerry',
|
||||
'cocoon' => 'O2 Cocoon',
|
||||
'blazer' => 'Treo',
|
||||
'lg' => 'LG',
|
||||
'amoi' => 'Amoi',
|
||||
'xda' => 'XDA',
|
||||
'mda' => 'MDA',
|
||||
'vario' => 'Vario',
|
||||
'htc' => 'HTC',
|
||||
'samsung' => 'Samsung',
|
||||
'sharp' => 'Sharp',
|
||||
'sie-' => 'Siemens',
|
||||
'alcatel' => 'Alcatel',
|
||||
'benq' => 'BenQ',
|
||||
'ipaq' => 'HP iPaq',
|
||||
'mot-' => 'Motorola',
|
||||
'playstation portable' => 'PlayStation Portable',
|
||||
'playstation 3' => 'PlayStation 3',
|
||||
'playstation vita' => 'PlayStation Vita',
|
||||
'hiptop' => 'Danger Hiptop',
|
||||
'nec-' => 'NEC',
|
||||
'panasonic' => 'Panasonic',
|
||||
'philips' => 'Philips',
|
||||
'sagem' => 'Sagem',
|
||||
'sanyo' => 'Sanyo',
|
||||
'spv' => 'SPV',
|
||||
'zte' => 'ZTE',
|
||||
'sendo' => 'Sendo',
|
||||
'nintendo dsi' => 'Nintendo DSi',
|
||||
'nintendo ds' => 'Nintendo DS',
|
||||
'nintendo 3ds' => 'Nintendo 3DS',
|
||||
'wii' => 'Nintendo Wii',
|
||||
'open web' => 'Open Web',
|
||||
'openweb' => 'OpenWeb',
|
||||
'meizu' => 'Meizu',
|
||||
'huawei' => 'Huawei',
|
||||
'xiaomi' => 'Xiaomi',
|
||||
'oppo' => 'Oppo',
|
||||
'vivo' => 'Vivo',
|
||||
'infinix' => 'Infinix',
|
||||
|
||||
// Operating Systems
|
||||
'android' => 'Android',
|
||||
'symbian' => 'Symbian',
|
||||
'SymbianOS' => 'SymbianOS',
|
||||
'elaine' => 'Palm',
|
||||
'series60' => 'Symbian S60',
|
||||
'windows ce' => 'Windows CE',
|
||||
|
||||
// Browsers
|
||||
'obigo' => 'Obigo',
|
||||
'netfront' => 'Netfront Browser',
|
||||
'openwave' => 'Openwave Browser',
|
||||
'mobilexplorer' => 'Mobile Explorer',
|
||||
'operamini' => 'Opera Mini',
|
||||
'opera mini' => 'Opera Mini',
|
||||
'opera mobi' => 'Opera Mobile',
|
||||
'fennec' => 'Firefox Mobile',
|
||||
|
||||
// Other
|
||||
'digital paths' => 'Digital Paths',
|
||||
'avantgo' => 'AvantGo',
|
||||
'xiino' => 'Xiino',
|
||||
'novarra' => 'Novarra Transcoder',
|
||||
'vodafone' => 'Vodafone',
|
||||
'docomo' => 'NTT DoCoMo',
|
||||
'o2' => 'O2',
|
||||
|
||||
// Fallback
|
||||
'mobile' => 'Generic Mobile',
|
||||
'wireless' => 'Generic Mobile',
|
||||
'j2me' => 'Generic Mobile',
|
||||
'midp' => 'Generic Mobile',
|
||||
'cldc' => 'Generic Mobile',
|
||||
'up.link' => 'Generic Mobile',
|
||||
'up.browser' => 'Generic Mobile',
|
||||
'smartphone' => 'Generic Mobile',
|
||||
'cellphone' => 'Generic Mobile'
|
||||
);
|
||||
|
||||
// There are hundreds of bots but these are the most common.
|
||||
$robots = array(
|
||||
'googlebot' => 'Googlebot',
|
||||
'msnbot' => 'MSNBot',
|
||||
'baiduspider' => 'Baiduspider',
|
||||
'bingbot' => 'Bing',
|
||||
'slurp' => 'Inktomi Slurp',
|
||||
'yahoo' => 'Yahoo',
|
||||
'ask jeeves' => 'Ask Jeeves',
|
||||
'fastcrawler' => 'FastCrawler',
|
||||
'infoseek' => 'InfoSeek Robot 1.0',
|
||||
'lycos' => 'Lycos',
|
||||
'yandex' => 'YandexBot',
|
||||
'mediapartners-google' => 'MediaPartners Google',
|
||||
'CRAZYWEBCRAWLER' => 'Crazy Webcrawler',
|
||||
'adsbot-google' => 'AdsBot Google',
|
||||
'feedfetcher-google' => 'Feedfetcher Google',
|
||||
'curious george' => 'Curious George',
|
||||
'ia_archiver' => 'Alexa Crawler',
|
||||
'MJ12bot' => 'Majestic-12',
|
||||
'Uptimebot' => 'Uptimebot',
|
||||
'UptimeRobot' => 'UptimeRobot'
|
||||
);
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Accounts extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
||||
if($this->session->userdata('role') != 'Admin'){
|
||||
show_error('Akses ditolak', 403);
|
||||
}
|
||||
|
||||
$data = [
|
||||
"active_menu" => "accounts",
|
||||
"parent_accounts" => $this->db->get('accounts')->result()
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('accounts/layout', $data);
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
public function get_data()
|
||||
{
|
||||
$this->dm->setTable('accounts')
|
||||
->setColumn(
|
||||
[null,'kode_akun','nama_akun','tipe','posisi','kategori',null],
|
||||
['kode_akun','nama_akun','tipe'],
|
||||
['kode_akun'=>'ASC']
|
||||
);
|
||||
|
||||
$list = $this->dm->get_datatables();
|
||||
|
||||
$data = [];
|
||||
$no = $_POST['start'];
|
||||
|
||||
foreach ($list as $row) {
|
||||
$no++;
|
||||
|
||||
$data[] = [
|
||||
$no,
|
||||
$row->kode_akun,
|
||||
$row->nama_akun,
|
||||
ucfirst($row->tipe),
|
||||
ucfirst($row->posisi),
|
||||
ucfirst($row->kategori),
|
||||
'
|
||||
<button class="btn btn-sm btn-warning btn-edit" data-id="'.$row->id.'">Edit</button>
|
||||
<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Delete</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"draw" => $_POST['draw'],
|
||||
"recordsTotal" => $this->dm->count_all(),
|
||||
"recordsFiltered" => $this->dm->count_filtered(),
|
||||
"data" => $data
|
||||
]);
|
||||
}
|
||||
|
||||
// ================= SAVE
|
||||
public function save()
|
||||
{
|
||||
$tipe = $this->input->post('tipe');
|
||||
|
||||
$data = [
|
||||
'kode_akun' => $this->input->post('kode_akun'),
|
||||
'nama_akun' => $this->input->post('nama_akun'),
|
||||
'tipe' => $tipe,
|
||||
'posisi' => in_array($tipe, ['asset','expense']) ? 'debit' : 'kredit',
|
||||
'kategori' => in_array($tipe, ['asset','liability','equity']) ? 'neraca' : 'laba_rugi',
|
||||
'parent_id' => $this->input->post('parent_id') ?: NULL
|
||||
];
|
||||
|
||||
$insert = $this->dm->setTable('accounts')->insert($data);
|
||||
|
||||
if($insert){
|
||||
log_activity(
|
||||
'Accounts',
|
||||
'create',
|
||||
'Menambah akun: '.$data['kode_akun'].' - '.$data['nama_akun']
|
||||
);
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => $insert ? true : false,
|
||||
'message' => $insert ? 'Data berhasil disimpan' : 'Gagal simpan'
|
||||
]);
|
||||
}
|
||||
|
||||
// ================= UPDATE
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
$tipe = $this->input->post('tipe');
|
||||
|
||||
$data = [
|
||||
'kode_akun' => $this->input->post('kode_akun'),
|
||||
'nama_akun' => $this->input->post('nama_akun'),
|
||||
'tipe' => $tipe,
|
||||
'posisi' => in_array($tipe, ['asset','expense']) ? 'debit' : 'kredit',
|
||||
'kategori' => in_array($tipe, ['asset','liability','equity']) ? 'neraca' : 'laba_rugi',
|
||||
'parent_id' => $this->input->post('parent_id') ?: NULL
|
||||
];
|
||||
|
||||
$update = $this->dm->setTable('accounts')->update($id, $data);
|
||||
|
||||
if($update){
|
||||
log_activity(
|
||||
'Accounts',
|
||||
'update',
|
||||
'Update akun ID '.$id.' menjadi: '.$data['kode_akun'].' - '.$data['nama_akun']
|
||||
);
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => $update ? true : false,
|
||||
'message' => $update ? 'Data berhasil diupdate' : 'Gagal update'
|
||||
]);
|
||||
}
|
||||
|
||||
public function detail($id)
|
||||
{
|
||||
$data = $this->dm->setTable('accounts')->find($id);
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
// cek apakah jadi parent
|
||||
$child = $this->db->where('parent_id',$id)->count_all_results('accounts');
|
||||
|
||||
if($child > 0){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Tidak bisa hapus, akun punya child'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$delete = $this->dm->setTable('accounts')->delete($id);
|
||||
|
||||
if($delete){
|
||||
log_activity(
|
||||
'Accounts',
|
||||
'delete',
|
||||
'Menghapus akun ID '.$id,
|
||||
'success'
|
||||
);
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => $delete ? true : false,
|
||||
'message' => $delete ? 'Data berhasil dihapus' : 'Gagal hapus'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Asset extends CI_Controller {
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct();
|
||||
$this->load->database();
|
||||
}
|
||||
|
||||
public function index(){
|
||||
$data = ["active_menu" => "asset"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('asset/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// ================= GET DATA =================
|
||||
public function get_data(){
|
||||
$data = $this->db
|
||||
->select('assets.*, lokasi_asset.nama as nama_lokasi')
|
||||
->from('assets')
|
||||
->join('lokasi_asset', 'lokasi_asset.id = assets.lokasi_asset_id', 'left')
|
||||
->order_by('assets.id','DESC')
|
||||
->get()
|
||||
->result();
|
||||
|
||||
$no = 1;
|
||||
$result = [];
|
||||
|
||||
foreach($data as $d){
|
||||
$result[] = [
|
||||
$no++,
|
||||
$d->tanggal_perolehan,
|
||||
$d->kode_asset ?? '-',
|
||||
$d->nama_asset,
|
||||
$d->nama_lokasi ?? '-',
|
||||
number_format($d->nilai_perolehan),
|
||||
$d->masa_manfaat . ' bln',
|
||||
number_format($d->penyusutan_per_bulan),
|
||||
$d->created_at,
|
||||
'
|
||||
<button class="btn btn-sm btn-info btn-detail mb-1 ml-1" data-id="'.$d->id.'"><i class="bi bi-eye"></i></button>
|
||||
<button class="btn btn-sm btn-warning btn-edit mb-1 ml-1" data-id="'.$d->id.'">Edit</button>
|
||||
<button class="btn btn-sm btn-danger btn-delete mb-1 ml-1" data-id="'.$d->id.'">Hapus</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode(['data'=>$result]);
|
||||
}
|
||||
|
||||
// ================= DETAIL ASSET + HISTORY =================
|
||||
public function detail($id)
|
||||
{
|
||||
$data = $this->db
|
||||
->select('a.*, la.nama AS nama_lokasi') // ambil field tambahan dari lokasi_asset
|
||||
->from('assets a')
|
||||
->join('lokasi_asset la', 'a.lokasi_asset_id = la.id', 'left')
|
||||
->where('a.id', $id)
|
||||
->get()
|
||||
->row();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
public function get_history($asset_id){
|
||||
$data = $this->db
|
||||
->where('asset_id', $asset_id)
|
||||
->order_by('created_at', 'DESC')
|
||||
->get('asset_mutations')
|
||||
->result();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
// ================= SAVE MANUAL (1 UNIT) =================
|
||||
public function save(){
|
||||
$harga = preg_replace('/\D/','',$this->input->post('harga'));
|
||||
$residu = preg_replace('/\D/','',$this->input->post('residu'));
|
||||
$masa = (int)$this->input->post('masa');
|
||||
$account_debit_id = (int)$this->input->post('account_asset');
|
||||
$account_kredit_id = (int)$this->input->post('account_kas');
|
||||
$lokasi_asset_id = (int)$this->input->post('lokasi_asset');
|
||||
$tanggal = $this->input->post('tanggal');
|
||||
$nama_asset = $this->input->post('nama_asset');
|
||||
$keterangan = $this->input->post('keterangan');
|
||||
|
||||
$nilai_perolehan = $harga * 1;
|
||||
$penyusutan = ($harga - $residu) / ($masa ?: 1);
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
$data = [
|
||||
'kode_asset' => 'AST-'.time(),
|
||||
'nama_asset' => $nama_asset,
|
||||
'harga_per_unit' => $harga,
|
||||
'nilai_perolehan' => $nilai_perolehan,
|
||||
'tanggal_perolehan' => $tanggal,
|
||||
'masa_manfaat' => $masa,
|
||||
'nilai_residu' => $residu,
|
||||
'penyusutan_per_bulan' => $penyusutan,
|
||||
'nilai_buku' => $nilai_perolehan,
|
||||
'sumber' => 'manual',
|
||||
'account_debit_id' => $account_debit_id,
|
||||
'account_kredit_id' => $account_kredit_id,
|
||||
'lokasi_asset_id' => $lokasi_asset_id,
|
||||
'keterangan' => $keterangan
|
||||
];
|
||||
|
||||
$this->db->insert('assets',$data);
|
||||
$asset_id = $this->db->insert_id();
|
||||
|
||||
// Journal
|
||||
$this->db->insert('journals',[
|
||||
'tanggal' => $tanggal,
|
||||
'no_ref' => 'AST-'.date('YmdHis').'-'.$asset_id,
|
||||
'keterangan' => 'Penambahan Aset '.$nama_asset,
|
||||
'ref_type' => 'assets',
|
||||
'ref_id' => $asset_id,
|
||||
'created_by' => $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$jid = $this->db->insert_id();
|
||||
|
||||
$this->db->insert('journal_details',[
|
||||
'journal_id' => $jid,
|
||||
'account_id' => $account_debit_id,
|
||||
'debit' => $nilai_perolehan,
|
||||
'kredit' => 0
|
||||
]);
|
||||
|
||||
$this->db->insert('journal_details',[
|
||||
'journal_id' => $jid,
|
||||
'account_id' => $account_kredit_id,
|
||||
'debit' => 0,
|
||||
'kredit' => $nilai_perolehan
|
||||
]);
|
||||
|
||||
// MUTATION PEROLEHAN
|
||||
$this->db->insert('asset_mutations',[
|
||||
'asset_id' => $asset_id,
|
||||
'tipe' => 'perolehan',
|
||||
'nilai' => $nilai_perolehan,
|
||||
'keterangan' => 'Perolehan manual: '.$keterangan
|
||||
]);
|
||||
|
||||
$this->db->trans_complete();
|
||||
echo json_encode(['status'=>true]);
|
||||
}
|
||||
|
||||
// ================= SAVE FROM STOCK =================
|
||||
public function save_from_stock(){
|
||||
$item_id = $this->input->post('item_id');
|
||||
$account_debit_id = (int)$this->input->post('account_asset');
|
||||
$lokasi_asset_id = (int)$this->input->post('s_lokasi_asset');
|
||||
$masa = (int)$this->input->post('s_masa');
|
||||
$residu = preg_replace('/\D/','',$this->input->post('s_residu'));
|
||||
$tanggal = $this->input->post('s_tanggal');
|
||||
|
||||
$item = $this->db->get_where('items',['id'=>$item_id])->row();
|
||||
|
||||
if(!$item){
|
||||
echo json_encode(['status'=>false,'message'=>'Item tidak ditemukan']);
|
||||
return;
|
||||
}
|
||||
|
||||
if($item->stok < 1){
|
||||
echo json_encode(['status'=>false,'message'=>'Stok tidak cukup']);
|
||||
return;
|
||||
}
|
||||
|
||||
$harga = $item->harga_beli;
|
||||
$nama_asset = $item->nama_barang;
|
||||
$nilai_perolehan = $harga;
|
||||
$penyusutan = ($harga - $residu) / ($masa ?: 1);
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
// INSERT ASSET
|
||||
$this->db->insert('assets',[
|
||||
'item_id' => $item_id,
|
||||
'kode_asset' => 'AST-'.time(),
|
||||
'nama_asset' => $nama_asset,
|
||||
'harga_per_unit' => $harga,
|
||||
'nilai_perolehan' => $nilai_perolehan,
|
||||
'tanggal_perolehan' => $tanggal,
|
||||
'masa_manfaat' => $masa,
|
||||
'nilai_residu' => $residu,
|
||||
'penyusutan_per_bulan' => $penyusutan,
|
||||
'nilai_buku' => $nilai_perolehan,
|
||||
'sumber' => 'gudang',
|
||||
'account_debit_id' => $account_debit_id,
|
||||
'account_kredit_id' => 21, // Persediaan
|
||||
'lokasi_asset_id' => $lokasi_asset_id
|
||||
]);
|
||||
|
||||
$asset_id = $this->db->insert_id();
|
||||
|
||||
// Journal
|
||||
$this->db->insert('journals',[
|
||||
'tanggal' => $tanggal,
|
||||
'no_ref' => 'AST-'.date('YmdHis').'-'.$asset_id,
|
||||
'keterangan' => 'Penambahan Aset dari Gudang '.$nama_asset,
|
||||
'ref_type' => 'assets',
|
||||
'ref_id' => $asset_id,
|
||||
'created_by' => $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$jid = $this->db->insert_id();
|
||||
|
||||
// Debit Asset
|
||||
$this->db->insert('journal_details',[
|
||||
'journal_id' => $jid,
|
||||
'account_id' => $account_debit_id,
|
||||
'debit' => $nilai_perolehan,
|
||||
'kredit' => 0
|
||||
]);
|
||||
|
||||
// Kredit Persediaan
|
||||
$this->db->insert('journal_details',[
|
||||
'journal_id' => $jid,
|
||||
'account_id' => 21,
|
||||
'debit' => 0,
|
||||
'kredit' => $nilai_perolehan
|
||||
]);
|
||||
|
||||
// UPDATE STOK ITEM (kurangi 1)
|
||||
$this->db->where('id', $item_id)
|
||||
->set('stok', 'stok-1', FALSE)
|
||||
->update('items');
|
||||
|
||||
// MUTATION DARI GUDANG
|
||||
$this->db->insert('asset_mutations',[
|
||||
'asset_id' => $asset_id,
|
||||
'tipe' => 'perolehan',
|
||||
'nilai' => $nilai_perolehan,
|
||||
'keterangan' => 'Perolehan dari gudang: '.$nama_asset
|
||||
]);
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
echo json_encode(['status'=>true]);
|
||||
}
|
||||
|
||||
// ================= UPDATE =================
|
||||
public function update(){
|
||||
$id = $this->input->post('id');
|
||||
$nama_asset = $this->input->post('nama_asset');
|
||||
$lokasi_asset_id = (int)$this->input->post('lokasi_asset');
|
||||
$keterangan = $this->input->post('keterangan');
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
$data = [
|
||||
'nama_asset' => $nama_asset,
|
||||
'lokasi_asset_id' => $lokasi_asset_id,
|
||||
'keterangan' => $keterangan
|
||||
];
|
||||
|
||||
$this->db->where('id',$id);
|
||||
$this->db->update('assets',$data);
|
||||
|
||||
// MUTATION EDIT
|
||||
$this->db->insert('asset_mutations',[
|
||||
'asset_id' => $id,
|
||||
'tipe' => 'penambahan',
|
||||
'nilai' => 0,
|
||||
'keterangan' => 'Edit asset: '.$nama_asset
|
||||
]);
|
||||
|
||||
$this->db->trans_complete();
|
||||
echo json_encode(['status'=>true]);
|
||||
}
|
||||
|
||||
// ================= DELETE =================
|
||||
public function delete(){
|
||||
$id = $this->input->post('id');
|
||||
$alasan = $this->input->post('alasan');
|
||||
$keterangan = $this->input->post('keterangan');
|
||||
|
||||
$asset = $this->db->get_where('assets',['id'=>$id])->row();
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
// Hapus journal
|
||||
$journals = $this->db->get_where('journals', ['ref_type'=>'assets', 'ref_id'=>$id])->result();
|
||||
foreach($journals as $j){
|
||||
$this->db->delete('journal_details', ['journal_id'=>$j->id]);
|
||||
$this->db->delete('journals', ['id'=>$j->id]);
|
||||
}
|
||||
|
||||
// Hapus asset
|
||||
$this->db->delete('assets',['id'=>$id]);
|
||||
|
||||
// MUTATION DELETE
|
||||
$this->db->insert('asset_mutations',[
|
||||
'asset_id' => $id,
|
||||
'tipe' => 'pengurangan',
|
||||
'nilai' => $asset->nilai_buku,
|
||||
'keterangan' => 'Penghapusan ('.$alasan.'): '.$keterangan
|
||||
]);
|
||||
|
||||
$this->db->trans_complete();
|
||||
echo json_encode(['status'=>true]);
|
||||
}
|
||||
|
||||
// ================= GET DATA SELECT =================
|
||||
public function get_accounts_kas(){
|
||||
$data = $this->db
|
||||
->where_in('sub_tipe', ['kas', 'hutang'])
|
||||
->order_by('kode_akun', 'ASC')
|
||||
->get('accounts')
|
||||
->result();
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
public function get_accounts_asset(){
|
||||
$data = $this->db
|
||||
->group_start()
|
||||
->like('nama_akun', 'Aset', 'after')
|
||||
->group_end()
|
||||
->order_by('kode_akun', 'ASC')
|
||||
->get('accounts')
|
||||
->result();
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
public function get_items(){
|
||||
$data = $this->db
|
||||
->where('stok > 0')
|
||||
->get('items')
|
||||
->result();
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
public function get_lokasi_asset(){
|
||||
$data = $this->db
|
||||
->get('lokasi_asset')
|
||||
->result();
|
||||
echo json_encode($data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class AttendanceWebhook extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
date_default_timezone_set('Asia/Jakarta');
|
||||
}
|
||||
|
||||
public function cdata()
|
||||
{
|
||||
// =========================
|
||||
// AMBIL SN MESIN
|
||||
// =========================
|
||||
$sn = $this->input->get('SN');
|
||||
|
||||
// =========================
|
||||
// RAW BODY DARI MESIN
|
||||
// =========================
|
||||
$body = file_get_contents('php://input');
|
||||
|
||||
// =========================
|
||||
// LOG DIRECTORY
|
||||
// =========================
|
||||
$logDir = APPPATH . 'logs/fingerprint/';
|
||||
|
||||
if (!is_dir($logDir)) {
|
||||
mkdir($logDir, 0777, true);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// FILE LOG
|
||||
// =========================
|
||||
$logFile = $logDir . date('Y-m-d') . '.log';
|
||||
|
||||
// =========================
|
||||
// FORMAT LOG HEADER
|
||||
// =========================
|
||||
$logText = "\n==================================================\n";
|
||||
$logText .= "TIME : " . date('Y-m-d H:i:s') . "\n";
|
||||
$logText .= "SN : " . $sn . "\n";
|
||||
$logText .= "IP : " . $this->input->ip_address() . "\n";
|
||||
$logText .= "DATA : \n";
|
||||
|
||||
// =========================
|
||||
// PARSE BARIS ABSENSI
|
||||
// =========================
|
||||
$lines = explode("\n", trim($body));
|
||||
|
||||
foreach ($lines as $line) {
|
||||
|
||||
$line = trim($line);
|
||||
|
||||
if (empty($line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$logText .= $line . "\n";
|
||||
|
||||
// contoh parsing
|
||||
$data = explode("\t", $line);
|
||||
|
||||
/*
|
||||
hasil biasanya:
|
||||
[0] => PIN/User ID
|
||||
[1] => Datetime
|
||||
[2] => Status
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
// =========================
|
||||
// SIMPAN LOG
|
||||
// =========================
|
||||
file_put_contents($logFile, $logText, FILE_APPEND);
|
||||
|
||||
// =========================
|
||||
// RESPONSE KE MESIN
|
||||
// =========================
|
||||
echo "OK";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Attendancemonitoring extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->database();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
"active_menu" => "attendance_monitoring"
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('employees/attendance_monitoring');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
public function get_data()
|
||||
{
|
||||
$date = $this->input->get('date');
|
||||
|
||||
if(!$date){
|
||||
$date = date('Y-m-d');
|
||||
}
|
||||
|
||||
$data = $this->db->query("
|
||||
SELECT
|
||||
a.*,
|
||||
e.employee_code,
|
||||
e.full_name,
|
||||
s.shift_name
|
||||
FROM k_attendances a
|
||||
LEFT JOIN k_employees e ON e.id = a.employee_id
|
||||
LEFT JOIN k_shifts s ON s.id = a.shift_id
|
||||
WHERE a.attendance_date = '$date'
|
||||
ORDER BY a.checkin_time DESC
|
||||
")->result();
|
||||
|
||||
$rows = [];
|
||||
$no = 1;
|
||||
|
||||
foreach($data as $d){
|
||||
|
||||
$rows[] = [
|
||||
$no++,
|
||||
$d->employee_code,
|
||||
$d->full_name,
|
||||
$d->shift_name,
|
||||
$d->checkin_time,
|
||||
$d->checkout_time,
|
||||
$d->attendance_status
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'data' => $rows
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Auth extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
if ($this->session->userdata('logged_in')) {
|
||||
redirect('dashboard');
|
||||
}
|
||||
|
||||
$this->load->view('auth/login');
|
||||
}
|
||||
|
||||
public function process_login()
|
||||
{
|
||||
$username = $this->input->post('username');
|
||||
$password = $this->input->post('password');
|
||||
|
||||
$user = $this->db->get_where('v_users', ['username' => $username])->row();
|
||||
|
||||
if ($user && password_verify($password, $user->password)) {
|
||||
|
||||
// Decode permissions
|
||||
$permissions = json_decode($user->permissions, true);
|
||||
if (!is_array($permissions)) {
|
||||
$permissions = [];
|
||||
}
|
||||
|
||||
$session_data = [
|
||||
'user_id' => $user->id,
|
||||
'nama' => $user->nama,
|
||||
'username' => $user->username,
|
||||
'role' => $user->nama_role,
|
||||
'permissions' => $permissions,
|
||||
'logged_in' => TRUE
|
||||
];
|
||||
|
||||
$this->session->set_userdata($session_data);
|
||||
|
||||
// 🔥 LOG LOGIN BERHASIL
|
||||
log_activity(
|
||||
'Auth',
|
||||
'login',
|
||||
'User '.$user->username.' berhasil login',
|
||||
'success'
|
||||
);
|
||||
|
||||
redirect('dashboard');
|
||||
|
||||
} else {
|
||||
|
||||
// 🔥 LOG LOGIN GAGAL
|
||||
log_activity(
|
||||
'Auth',
|
||||
'login_failed',
|
||||
'Login gagal untuk username: '.$username,
|
||||
'failed'
|
||||
);
|
||||
|
||||
$this->session->set_flashdata('error', 'Username atau Password salah!');
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function logout()
|
||||
{
|
||||
$username = $this->session->userdata('username');
|
||||
|
||||
// 🔥 LOG LOGOUT (SEBELUM DESTROY SESSION)
|
||||
log_activity(
|
||||
'Auth',
|
||||
'logout',
|
||||
'User '.$username.' logout',
|
||||
'success'
|
||||
);
|
||||
|
||||
$this->session->sess_destroy();
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Basejurnal extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
// ================= INDEX
|
||||
public function index()
|
||||
{
|
||||
|
||||
if($this->session->userdata('role') != 'Admin'){
|
||||
show_error('Akses ditolak', 403);
|
||||
}
|
||||
|
||||
$data = [
|
||||
"active_menu" => "basejurnal"
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('basejurnal/layout', $data);
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// ================= DATATABLE
|
||||
public function get_data()
|
||||
{
|
||||
$this->dm->setTable('base_journal')
|
||||
->setColumn(
|
||||
[null,'kode','nama','deskripsi','is_active',null],
|
||||
['kode','nama'],
|
||||
['id'=>'DESC']
|
||||
);
|
||||
|
||||
$list = $this->dm->get_datatables();
|
||||
|
||||
$data = [];
|
||||
$no = $_POST['start'];
|
||||
|
||||
foreach ($list as $row) {
|
||||
$no++;
|
||||
|
||||
$status = $row->is_active ? 'Aktif' : 'Nonaktif';
|
||||
|
||||
$data[] = [
|
||||
$no,
|
||||
$row->kode,
|
||||
$row->nama,
|
||||
$row->deskripsi,
|
||||
$status,
|
||||
'
|
||||
<button class="btn btn-sm btn-warning btn-edit" data-id="'.$row->id.'">Edit</button>
|
||||
<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Hapus</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"draw" => $_POST['draw'],
|
||||
"recordsTotal" => $this->dm->count_all(),
|
||||
"recordsFiltered" => $this->dm->count_filtered(),
|
||||
"data" => $data
|
||||
]);
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
$this->db->trans_start();
|
||||
|
||||
$kode = trim($this->input->post('kode'));
|
||||
$nama = trim($this->input->post('nama'));
|
||||
|
||||
if(empty($kode) || empty($nama)){
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Kode & Nama wajib diisi'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$header = [
|
||||
'kode' => $kode,
|
||||
'nama' => $nama,
|
||||
'deskripsi' => $this->input->post('deskripsi'),
|
||||
'is_active' => 1
|
||||
];
|
||||
|
||||
$this->dm->setTable('base_journal')->insert($header);
|
||||
$base_id = $this->db->insert_id();
|
||||
|
||||
$accounts = $this->input->post('account_id');
|
||||
$posisi = $this->input->post('posisi');
|
||||
|
||||
if(!empty($accounts)){
|
||||
$detail = [];
|
||||
|
||||
foreach ($accounts as $i => $acc) {
|
||||
if(empty($acc)) continue;
|
||||
|
||||
$detail[] = [
|
||||
'base_journal_id' => $base_id,
|
||||
'account_id' => $acc,
|
||||
'posisi' => $posisi[$i] ?? 'debit',
|
||||
'urutan' => $i + 1
|
||||
];
|
||||
}
|
||||
|
||||
if(!empty($detail)){
|
||||
$this->db->insert_batch('base_journal_detail', $detail);
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
if (!$this->db->trans_status()) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Gagal simpan data'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
log_activity(
|
||||
'base_journal',
|
||||
'create',
|
||||
'Membuat base journal kode: '.$kode,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Data berhasil disimpan'
|
||||
]);
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
|
||||
if(empty($id)){
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'ID tidak valid'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
$header = [
|
||||
'kode' => trim($this->input->post('kode')),
|
||||
'nama' => trim($this->input->post('nama')),
|
||||
'deskripsi' => $this->input->post('deskripsi'),
|
||||
];
|
||||
|
||||
$this->dm->setTable('base_journal')->update($id, $header);
|
||||
|
||||
// 🔥 DELETE OLD DETAIL
|
||||
$this->db->where('base_journal_id', $id)->delete('base_journal_detail');
|
||||
|
||||
// 🔥 INSERT NEW DETAIL
|
||||
$accounts = $this->input->post('account_id');
|
||||
$posisi = $this->input->post('posisi');
|
||||
|
||||
if(!empty($accounts)){
|
||||
$detail = [];
|
||||
|
||||
foreach ($accounts as $i => $acc) {
|
||||
if(empty($acc)) continue;
|
||||
|
||||
$detail[] = [
|
||||
'base_journal_id' => $id,
|
||||
'account_id' => $acc,
|
||||
'posisi' => $posisi[$i] ?? 'debit',
|
||||
'urutan' => $i + 1
|
||||
];
|
||||
}
|
||||
|
||||
if(!empty($detail)){
|
||||
$this->db->insert_batch('base_journal_detail', $detail);
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
if (!$this->db->trans_status()) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Gagal update data'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
log_activity(
|
||||
'base_journal',
|
||||
'update',
|
||||
'Mengubah base journal ID: '.$id.' (kode: '.$header['kode'].')',
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Data berhasil diupdate'
|
||||
]);
|
||||
}
|
||||
|
||||
// ================= DETAIL
|
||||
public function detail($id)
|
||||
{
|
||||
$header = $this->dm->setTable('base_journal')->find($id);
|
||||
|
||||
$detail = $this->db
|
||||
->select('d.*, a.nama_akun as account_name')
|
||||
->from('base_journal_detail d')
|
||||
->join('accounts a','a.id = d.account_id','left') // <-- GANTI DI SINI
|
||||
->where('d.base_journal_id',$id)
|
||||
->order_by('d.urutan','ASC')
|
||||
->get()
|
||||
->result();
|
||||
|
||||
echo json_encode([
|
||||
'header' => $header,
|
||||
'detail' => $detail
|
||||
]);
|
||||
}
|
||||
|
||||
public function delete($id = null)
|
||||
{
|
||||
// set response JSON
|
||||
$this->output->set_content_type('application/json');
|
||||
|
||||
if (empty($id)) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'ID tidak valid'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
// hapus detail dulu
|
||||
$this->db->where('base_journal_id', $id)->delete('base_journal_detail');
|
||||
|
||||
// hapus header
|
||||
$delete = $this->dm->setTable('base_journal')->delete($id);
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
if (!$this->db->trans_status() || !$delete) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Gagal hapus data'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// ================= LOG ACTIVITY =================
|
||||
log_activity(
|
||||
'base_journal',
|
||||
'delete',
|
||||
'Menghapus base journal ID: '.$id,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Data berhasil dihapus'
|
||||
]);
|
||||
}
|
||||
|
||||
public function get_list_account()
|
||||
{
|
||||
$data = $this->db->select('id, nama_akun, kode_akun')
|
||||
->from('accounts') // sesuaikan tabel kamu
|
||||
->order_by('kode_akun','ASC')
|
||||
->get()
|
||||
->result();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Bukubesar extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
||||
if($this->session->userdata('role') != 'Admin'){
|
||||
show_error('Akses ditolak', 403);
|
||||
}
|
||||
|
||||
$data = ["active_menu" => "buku_besar"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('buku_besar/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET ACCOUNTS (FILTER)
|
||||
// =========================
|
||||
public function get_accounts()
|
||||
{
|
||||
$data = $this->dm->setTable('accounts')
|
||||
->order_by('kode_akun','ASC')
|
||||
->get();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET DATA BUKU BESAR
|
||||
// =========================
|
||||
public function get_data()
|
||||
{
|
||||
$account_id = $this->input->get('account_id');
|
||||
$start = $this->input->get('start_date');
|
||||
$end = $this->input->get('end_date');
|
||||
|
||||
$this->db->select('
|
||||
journals.tanggal,
|
||||
journals.no_ref,
|
||||
journals.keterangan,
|
||||
journal_details.debit,
|
||||
journal_details.kredit,
|
||||
accounts.nama_akun,
|
||||
accounts.tipe
|
||||
');
|
||||
$this->db->from('journal_details');
|
||||
$this->db->join('journals','journals.id = journal_details.journal_id');
|
||||
$this->db->join('accounts','accounts.id = journal_details.account_id');
|
||||
|
||||
if ($account_id) {
|
||||
$this->db->where('journal_details.account_id', $account_id);
|
||||
}
|
||||
|
||||
if ($start && $end) {
|
||||
$this->db->where('journals.tanggal >=', $start);
|
||||
$this->db->where('journals.tanggal <=', $end);
|
||||
}
|
||||
// 🔥 FILTER DEBIT/KREDIT TIDAK BOLEH 0 SEMUA
|
||||
$this->db->group_start();
|
||||
$this->db->where('journal_details.debit >', 0);
|
||||
$this->db->or_where('journal_details.kredit >', 0);
|
||||
$this->db->group_end();
|
||||
|
||||
$this->db->order_by('journals.tanggal','ASC');
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
// =========================
|
||||
// HITUNG SALDO BERJALAN
|
||||
// =========================
|
||||
$saldo = 0;
|
||||
$result = [];
|
||||
|
||||
foreach ($rows as $r) {
|
||||
|
||||
// LOGIKA SALDO BERDASARKAN TIPE AKUN
|
||||
if (in_array($r->tipe, ['asset','expense'])) {
|
||||
$saldo += ($r->debit - $r->kredit);
|
||||
} else {
|
||||
$saldo += ($r->kredit - $r->debit);
|
||||
}
|
||||
|
||||
$result[] = [
|
||||
'tanggal' => $r->tanggal,
|
||||
'no_ref' => $r->no_ref,
|
||||
'keterangan' => $r->keterangan,
|
||||
'debit' => $r->debit,
|
||||
'kredit' => $r->kredit,
|
||||
'saldo' => $saldo
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Cameraqrscan extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
|
||||
// Cek apakah user sudah login
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('login');
|
||||
}
|
||||
}
|
||||
|
||||
public function index($type = 'masuk')
|
||||
{
|
||||
// pastikan hanya masuk/keluar
|
||||
$type = strtolower($type);
|
||||
if (!in_array($type, ['masuk', 'keluar'])) {
|
||||
show_404();
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [
|
||||
"active_menu" => "",
|
||||
"scan_type" => $type // passing ke view
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('scan/qr_scan', $data);
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
public function get_data()
|
||||
{
|
||||
$qr_code = $this->input->post('qr_code');
|
||||
$scan_type = $this->input->post('scan_type'); // masuk / keluar
|
||||
|
||||
if (!$qr_code) {
|
||||
echo json_encode(['status' => false, 'message' => 'QR Code tidak ditemukan']);
|
||||
return;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// AMBIL DATA SISWA
|
||||
// ============================================================
|
||||
$siswa = $this->db->get_where('v_siswa', ['qr_id' => $qr_code])->row_array();
|
||||
|
||||
if (!$siswa) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Data siswa tidak ditemukan'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$id_siswa = $siswa['id'];
|
||||
$id_kelas = $siswa['id_kelas'];
|
||||
$id_kamar = $siswa['id_kamar'];
|
||||
|
||||
// ============================================================
|
||||
// CEGAH DUPLIKAT 5 MENIT (PostgreSQL)
|
||||
// ============================================================
|
||||
// Hitung waktu 5 menit yang lalu
|
||||
$datetimeNow = date('Y-m-d H:i:s');
|
||||
$datetime5MenitLalu = date('Y-m-d H:i:s', strtotime('-5 minutes'));
|
||||
|
||||
$cek = $this->db->query("
|
||||
SELECT id
|
||||
FROM kunjungan
|
||||
WHERE id_siswa = ?
|
||||
AND created_at >= ?
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
", [$id_siswa, $datetime5MenitLalu])->row_array();
|
||||
|
||||
if ($cek) {
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'data' => $siswa,
|
||||
'scan_type' => $scan_type,
|
||||
'message' => "Sudah tercatat dalam 5 menit terakhir"
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// AMBIL TEMPLATE PESAN
|
||||
// ============================================================
|
||||
$template = $this->db->get_where('template_pesan', ['jenis' => $scan_type])->row_array();
|
||||
|
||||
if (!$template) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Template pesan tidak ditemukan => ' . $scan_type
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$pesan = $template['isi_template'];
|
||||
$pesanType = $template['type'];
|
||||
|
||||
|
||||
// ============================================================
|
||||
// REPLACE TEMPLATE {{column}}
|
||||
// ============================================================
|
||||
foreach ($siswa as $key => $value) {
|
||||
$pesan = str_replace('{{'.$key.'}}', $value, $pesan);
|
||||
}
|
||||
|
||||
// Tambahan otomatis
|
||||
$pesan = str_replace('{{tanggal}}', date('Y-m-d'), $pesan);
|
||||
$pesan = str_replace('{{jam}}', date('H:i:s'), $pesan);
|
||||
|
||||
|
||||
// ============================================================
|
||||
// INSERT KUNJUNGAN
|
||||
// ============================================================
|
||||
$this->db->insert('kunjungan', [
|
||||
'id_siswa' => $id_siswa,
|
||||
'type' => $scan_type,
|
||||
'id_users' => $this->session->userdata('user_id'),
|
||||
'id_kelas' => $id_kelas,
|
||||
'id_kamar' => $id_kamar,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'media_type' => 'qr'
|
||||
]);
|
||||
|
||||
$new_id = $this->db->insert_id();
|
||||
|
||||
|
||||
// ============================================================
|
||||
// INSERT NOTIFIKASI WA
|
||||
// ============================================================
|
||||
$this->db->insert('notifikasi', [
|
||||
'type' => $pesanType,
|
||||
'pesan' => $pesan,
|
||||
'status' => 'pending',
|
||||
'nomor_whatsapp' => $siswa['nomor_whatsapp'],
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
|
||||
// ============================================================
|
||||
// RESPONSE
|
||||
// ============================================================
|
||||
$info = ($scan_type === 'masuk')
|
||||
? "Berhasil scan MASUK"
|
||||
: "Berhasil scan KELUAR";
|
||||
|
||||
// tampilkan data lengkap dari v_kunjungan
|
||||
$dataSiswa = $this->db->get_where('v_kunjungan_detail', ['id' => $new_id])->row();
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'data' => $dataSiswa,
|
||||
'scan_type' => $scan_type,
|
||||
'message' => $info
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Cronjob extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->database();
|
||||
|
||||
// ONLY CLI ACCESS
|
||||
if (!$this->input->is_cli_request()) {
|
||||
exit('No direct access allowed');
|
||||
}
|
||||
}
|
||||
|
||||
public function generate_insight()
|
||||
{
|
||||
$period = date('Y-m');
|
||||
|
||||
// =====================================================
|
||||
// 🔥 REPLACE MODE (hapus data lama dulu)
|
||||
// =====================================================
|
||||
$this->db->where('period', $period);
|
||||
$this->db->delete('ai_insights');
|
||||
|
||||
// =====================================================
|
||||
// 1. FINANCE - OVERDUE INVOICE
|
||||
// =====================================================
|
||||
$overdue = $this->db->query("
|
||||
SELECT COUNT(*) as total
|
||||
FROM invoices
|
||||
WHERE status != 'paid'
|
||||
AND jatuh_tempo < CURDATE()
|
||||
AND deleted_at IS NULL
|
||||
")->row()->total;
|
||||
|
||||
if ($overdue > 0) {
|
||||
$this->db->insert('ai_insights', [
|
||||
'type' => 'finance',
|
||||
'severity' => 'warning',
|
||||
'message' => "$overdue invoice sudah melewati jatuh tempo",
|
||||
'meta' => json_encode([
|
||||
'overdue_count' => (int)$overdue
|
||||
]),
|
||||
'period' => $period
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 2. FINANCE - CASHFLOW BULAN INI
|
||||
// =====================================================
|
||||
$cash = $this->db->query("
|
||||
SELECT COALESCE(SUM(jd.debit),0) as cash_in
|
||||
FROM journal_details jd
|
||||
JOIN journals j ON j.id = jd.journal_id
|
||||
WHERE MONTH(j.tanggal) = MONTH(CURDATE())
|
||||
AND YEAR(j.tanggal) = YEAR(CURDATE())
|
||||
")->row()->cash_in;
|
||||
|
||||
if ($cash > 0) {
|
||||
$this->db->insert('ai_insights', [
|
||||
'type' => 'finance',
|
||||
'severity' => ($cash > 10000000) ? 'info' : 'warning',
|
||||
'message' => "Cashflow bulan ini Rp " . number_format($cash),
|
||||
'meta' => json_encode([
|
||||
'cash_in' => (float)$cash
|
||||
]),
|
||||
'period' => $period
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 3. STOCK - KRITIS
|
||||
// =====================================================
|
||||
$stocks = $this->db->query("
|
||||
SELECT
|
||||
i.kode_id,
|
||||
k.nama_barang,
|
||||
SUM(i.stok) as total_stok,
|
||||
k.limit_stock
|
||||
FROM items i
|
||||
JOIN kode_barang k ON k.id = i.kode_id
|
||||
GROUP BY i.kode_id, k.nama_barang, k.limit_stock
|
||||
HAVING total_stok <= k.limit_stock
|
||||
")->result();
|
||||
|
||||
foreach ($stocks as $s) {
|
||||
$this->db->insert('ai_insights', [
|
||||
'type' => 'stock',
|
||||
'severity' => 'critical',
|
||||
'message' => "Stok {$s->nama_barang} kritis ({$s->total_stok})",
|
||||
'meta' => json_encode([
|
||||
'kode_id' => $s->kode_id,
|
||||
'item' => $s->nama_barang,
|
||||
'stok' => (int)$s->total_stok,
|
||||
'limit' => (int)$s->limit_stock
|
||||
]),
|
||||
'period' => $period
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 4. CUSTOMER - PAYMENT RISK
|
||||
// =====================================================
|
||||
$lateCustomers = $this->db->query("
|
||||
SELECT
|
||||
c.nama,
|
||||
COUNT(i.id) as total_invoice
|
||||
FROM invoices i
|
||||
JOIN customers c ON c.id = i.customer_id
|
||||
WHERE i.status != 'paid'
|
||||
AND i.jatuh_tempo < CURDATE()
|
||||
GROUP BY i.customer_id
|
||||
HAVING total_invoice > 2
|
||||
")->result();
|
||||
|
||||
foreach ($lateCustomers as $c) {
|
||||
$this->db->insert('ai_insights', [
|
||||
'type' => 'customer',
|
||||
'severity' => 'warning',
|
||||
'message' => "Customer {$c->nama} memiliki {$c->total_invoice} invoice overdue",
|
||||
'meta' => json_encode([
|
||||
'customer' => $c->nama,
|
||||
'overdue_invoice' => (int)$c->total_invoice
|
||||
]),
|
||||
'period' => $period
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// RESPONSE
|
||||
// =====================================================
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'AI Insight generated (REPLACE MODE)',
|
||||
'period' => $period
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Customers extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data = ["active_menu" => "customers"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('customers/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DATATABLE
|
||||
// =========================
|
||||
public function get_data()
|
||||
{
|
||||
$this->dm->setTable('customers')
|
||||
->setColumn(
|
||||
[null,'nama','alamat','telp','email',null],
|
||||
['nama','alamat','telp','email'],
|
||||
['id'=>'DESC']
|
||||
);
|
||||
|
||||
$list = $this->dm->get_datatables();
|
||||
|
||||
$data = [];
|
||||
$no = $_POST['start'];
|
||||
|
||||
foreach ($list as $row) {
|
||||
$no++;
|
||||
|
||||
$aksi = '
|
||||
<button class="btn btn-sm btn-warning btn-edit" data-id="'.$row->id.'">Edit</button>
|
||||
<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Delete</button>
|
||||
';
|
||||
|
||||
$data[] = [
|
||||
$no,
|
||||
$row->nama,
|
||||
$row->alamat,
|
||||
$row->telp,
|
||||
$row->email,
|
||||
$aksi
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"draw" => $_POST['draw'],
|
||||
"recordsTotal" => $this->dm->count_all(),
|
||||
"recordsFiltered" => $this->dm->count_filtered(),
|
||||
"data" => $data
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// SAVE
|
||||
// =========================
|
||||
public function save()
|
||||
{
|
||||
$data = [
|
||||
'nama' => $this->input->post('nama'),
|
||||
'alamat' => $this->input->post('alamat'),
|
||||
'telp' => $this->input->post('telp'),
|
||||
'email' => $this->input->post('email')
|
||||
];
|
||||
|
||||
if (!$data['nama']) {
|
||||
echo json_encode(['status'=>false,'message'=>'Nama wajib diisi']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->dm->setTable('customers')->insert($data);
|
||||
|
||||
// ================= LOG ACTIVITY =================
|
||||
log_activity(
|
||||
'customers',
|
||||
'create',
|
||||
'Menambahkan customer: '.$data['nama'],
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Data berhasil disimpan']);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DETAIL
|
||||
// =========================
|
||||
public function detail($id)
|
||||
{
|
||||
$data = $this->dm->setTable('customers')->get_by_id($id);
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// UPDATE
|
||||
// =========================
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
|
||||
$data = [
|
||||
'nama' => $this->input->post('nama'),
|
||||
'alamat' => $this->input->post('alamat'),
|
||||
'telp' => $this->input->post('telp'),
|
||||
'email' => $this->input->post('email')
|
||||
];
|
||||
|
||||
$this->dm->setTable('customers')->update($id, $data);
|
||||
|
||||
// ================= LOG ACTIVITY =================
|
||||
log_activity(
|
||||
'customers',
|
||||
'update',
|
||||
'Mengubah customer ID: '.$id.' ('.$data['nama'].')',
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Data berhasil diupdate']);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DELETE
|
||||
// =========================
|
||||
public function delete($id)
|
||||
{
|
||||
$this->dm->setTable('customers')->delete($id);
|
||||
|
||||
// ================= LOG ACTIVITY =================
|
||||
log_activity(
|
||||
'customers',
|
||||
'delete',
|
||||
'Menghapus customer: '.($customer->nama ?? 'ID '.$id),
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Data berhasil dihapus']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Dashboard extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->library('session');
|
||||
|
||||
// Cek apakah user sudah login
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->db->select('
|
||||
accounts.id,
|
||||
accounts.kode_akun,
|
||||
accounts.nama_akun,
|
||||
accounts.tipe,
|
||||
COALESCE(SUM(journal_details.debit),0) as debit,
|
||||
COALESCE(SUM(journal_details.kredit),0) as kredit
|
||||
');
|
||||
$this->db->from('accounts');
|
||||
$this->db->join('journal_details','accounts.id = journal_details.account_id','left');
|
||||
$this->db->where('accounts.kategori','laba_rugi');
|
||||
$this->db->where('accounts.is_active',1);
|
||||
$this->db->group_by('accounts.id');
|
||||
$this->db->order_by('accounts.kode_akun','ASC');
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
$revenue = 0;
|
||||
$expense = 0;
|
||||
|
||||
foreach ($rows as $r) {
|
||||
|
||||
// 🔥 NORMALISASI SALDO BERDASARKAN POSISI
|
||||
if ($r->tipe == 'revenue') {
|
||||
$saldo = $r->kredit - $r->debit;
|
||||
$revenue += $saldo;
|
||||
}
|
||||
|
||||
if ($r->tipe == 'expense') {
|
||||
$saldo = $r->debit - $r->kredit;
|
||||
$expense += $saldo;
|
||||
}
|
||||
}
|
||||
|
||||
$summary = [
|
||||
'total_revenue' => $revenue,
|
||||
'total_expense' => $expense,
|
||||
'net_profit' => $revenue - $expense
|
||||
];
|
||||
|
||||
$today = date('Y-m');
|
||||
$ai_insight = $this->db
|
||||
->select('type, severity, message, meta, created_at')
|
||||
->where('period', $today)
|
||||
->order_by("
|
||||
CASE severity
|
||||
WHEN 'critical' THEN 1
|
||||
WHEN 'warning' THEN 2
|
||||
WHEN 'info' THEN 3
|
||||
END
|
||||
", '', false)
|
||||
->order_by('created_at', 'DESC')
|
||||
->limit(20)
|
||||
->get('ai_insights')
|
||||
->result();
|
||||
|
||||
$data = [
|
||||
"active_menu" => "dashboard",
|
||||
"summary" => $summary,
|
||||
"ai_insight" => $ai_insight
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('dashboard/layout', $data);
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
public function get_activity()
|
||||
{
|
||||
$this->db->select('activity_logs.*, users.nama');
|
||||
$this->db->from('activity_logs');
|
||||
$this->db->join('users','users.id = activity_logs.user_id','left');
|
||||
|
||||
if ($this->session->userdata('role') != 'Admin') {
|
||||
$this->db->where('user_id',$this->session->userdata('user_id'));
|
||||
}
|
||||
|
||||
$this->db->order_by('created_at','DESC');
|
||||
$this->db->limit(10);
|
||||
|
||||
$data = $this->db->get()->result();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
public function log_activity()
|
||||
{
|
||||
$data = [
|
||||
"active_menu" => "dashboard"
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('dashboard/activity_logs', $data);
|
||||
$this->load->view('partials/footer');
|
||||
|
||||
}
|
||||
|
||||
public function get_activity_datatable()
|
||||
{
|
||||
$this->load->database();
|
||||
|
||||
$draw = $this->input->post('draw');
|
||||
$start = $this->input->post('start');
|
||||
$length = $this->input->post('length');
|
||||
$search = $this->input->post('search')['value'] ?? '';
|
||||
|
||||
// =========================
|
||||
// BASE QUERY
|
||||
// =========================
|
||||
$this->db->select('
|
||||
activity_logs.*,
|
||||
users.nama
|
||||
');
|
||||
$this->db->from('activity_logs');
|
||||
$this->db->join('users', 'users.id = activity_logs.user_id', 'left');
|
||||
|
||||
// =========================
|
||||
// SEARCH
|
||||
// =========================
|
||||
if (!empty($search)) {
|
||||
$this->db->group_start();
|
||||
$this->db->like('activity_logs.module', $search);
|
||||
$this->db->or_like('activity_logs.action', $search);
|
||||
$this->db->or_like('activity_logs.description', $search);
|
||||
$this->db->or_like('activity_logs.status', $search);
|
||||
$this->db->or_like('users.nama', $search);
|
||||
$this->db->group_end();
|
||||
}
|
||||
|
||||
// =========================
|
||||
// COUNT FILTERED
|
||||
// =========================
|
||||
$filtered_query = clone $this->db;
|
||||
$recordsFiltered = $filtered_query->count_all_results('', false);
|
||||
|
||||
// =========================
|
||||
// ORDER
|
||||
// =========================
|
||||
$this->db->order_by('activity_logs.id', 'DESC');
|
||||
|
||||
// =========================
|
||||
// LIMIT
|
||||
// =========================
|
||||
if ($length != -1) {
|
||||
$this->db->limit($length, $start);
|
||||
}
|
||||
|
||||
$query = $this->db->get();
|
||||
$data = $query->result();
|
||||
|
||||
// =========================
|
||||
// TOTAL RECORD
|
||||
// =========================
|
||||
$recordsTotal = $this->db->count_all('activity_logs');
|
||||
|
||||
// =========================
|
||||
// FORMAT OUTPUT
|
||||
// =========================
|
||||
$result = [];
|
||||
|
||||
foreach ($data as $row) {
|
||||
$result[] = [
|
||||
'created_at' => $row->created_at,
|
||||
'nama' => $row->nama ?? 'System',
|
||||
'module' => $row->module,
|
||||
'action' => $row->action,
|
||||
'description' => $row->description,
|
||||
'status' => $row->status,
|
||||
'ip_address' => $row->ip_address
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"draw" => intval($draw),
|
||||
"recordsTotal" => $recordsTotal,
|
||||
"recordsFiltered" => $recordsFiltered,
|
||||
"data" => $result
|
||||
]);
|
||||
}
|
||||
|
||||
public function get_chart()
|
||||
{
|
||||
$year = $this->input->get('year');
|
||||
|
||||
// 🔥 DEFAULT: tahun berjalan
|
||||
if (empty($year)) {
|
||||
$year = date('Y');
|
||||
}
|
||||
|
||||
$this->db->select('
|
||||
journals.tanggal,
|
||||
accounts.tipe,
|
||||
SUM(journal_details.debit) as total_debit,
|
||||
SUM(journal_details.kredit) as total_kredit
|
||||
');
|
||||
$this->db->from('journal_details');
|
||||
$this->db->join('journals', 'journals.id = journal_details.journal_id', 'left');
|
||||
$this->db->join('accounts', 'accounts.id = journal_details.account_id', 'left');
|
||||
$this->db->where('accounts.kategori', 'laba_rugi');
|
||||
$this->db->where('accounts.is_active', 1);
|
||||
|
||||
// 🔥 pakai tahun default / filter
|
||||
$this->db->where('YEAR(journals.tanggal)', $year);
|
||||
|
||||
$this->db->group_by(['journals.tanggal', 'accounts.tipe']);
|
||||
$this->db->order_by('journals.tanggal', 'ASC');
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
$map = [];
|
||||
|
||||
foreach ($rows as $r) {
|
||||
|
||||
$date = $r->tanggal;
|
||||
|
||||
if (!isset($map[$date])) {
|
||||
$map[$date] = [
|
||||
'revenue' => 0,
|
||||
'expense' => 0
|
||||
];
|
||||
}
|
||||
|
||||
if ($r->tipe == 'revenue') {
|
||||
$map[$date]['revenue'] += ($r->total_kredit - $r->total_debit);
|
||||
}
|
||||
|
||||
if ($r->tipe == 'expense') {
|
||||
$map[$date]['expense'] += ($r->total_debit - $r->total_kredit);
|
||||
}
|
||||
}
|
||||
|
||||
$labels = [];
|
||||
$revenue = [];
|
||||
$expense = [];
|
||||
|
||||
foreach ($map as $date => $val) {
|
||||
$labels[] = $date;
|
||||
$revenue[] = (float)$val['revenue'];
|
||||
$expense[] = (float)$val['expense'];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'year' => $year, // optional biar debugging enak
|
||||
'labels' => $labels,
|
||||
'revenue' => $revenue,
|
||||
'expense' => $expense
|
||||
]);
|
||||
}
|
||||
|
||||
public function get_years()
|
||||
{
|
||||
$this->db->select('DISTINCT YEAR(tanggal) as year');
|
||||
$this->db->from('journals');
|
||||
$this->db->order_by('year', 'DESC');
|
||||
|
||||
$data = $this->db->get()->result();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,450 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Employees extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->database();
|
||||
$this->load->helper(['url', 'file']);
|
||||
|
||||
date_default_timezone_set('Asia/Jakarta');
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// INDEX
|
||||
// =========================================================
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
"active_menu" => "employees"
|
||||
];
|
||||
|
||||
$data['departments'] = $this->db
|
||||
->where('is_active',1)
|
||||
->order_by('department_name','ASC')
|
||||
->get('k_departments')
|
||||
->result();
|
||||
|
||||
$data['positions'] = $this->db
|
||||
->where('is_active',1)
|
||||
->order_by('position_name','ASC')
|
||||
->get('k_positions')
|
||||
->result();
|
||||
|
||||
$data['branches'] = $this->db
|
||||
->order_by('branch_name','ASC')
|
||||
->get('k_branches')
|
||||
->result();
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('employees/employees', $data);
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// GET ALL
|
||||
// =========================================================
|
||||
public function getAll()
|
||||
{
|
||||
try {
|
||||
|
||||
$data = $this->db
|
||||
->select("
|
||||
e.*,
|
||||
|
||||
d.department_name,
|
||||
p.position_name,
|
||||
b.branch_name
|
||||
")
|
||||
->from('k_employees e')
|
||||
|
||||
->join(
|
||||
'k_departments d',
|
||||
'd.id = e.department_id',
|
||||
'left'
|
||||
)
|
||||
|
||||
->join(
|
||||
'k_positions p',
|
||||
'p.id = e.position_id',
|
||||
'left'
|
||||
)
|
||||
|
||||
->join(
|
||||
'k_branches b',
|
||||
'b.id = e.branch_id',
|
||||
'left'
|
||||
)
|
||||
|
||||
->order_by('e.department_id','ASC')
|
||||
->get()
|
||||
->result();
|
||||
|
||||
return $this->json([
|
||||
'status' => true,
|
||||
'data' => $data
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage(),
|
||||
'data' => []
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// DETAIL
|
||||
// =========================================================
|
||||
public function detail($id = null)
|
||||
{
|
||||
try {
|
||||
|
||||
$data = $this->db
|
||||
->select("
|
||||
e.*,
|
||||
|
||||
d.department_name,
|
||||
p.position_name,
|
||||
b.branch_name
|
||||
")
|
||||
->from('k_employees e')
|
||||
|
||||
->join(
|
||||
'k_departments d',
|
||||
'd.id = e.department_id',
|
||||
'left'
|
||||
)
|
||||
|
||||
->join(
|
||||
'k_positions p',
|
||||
'p.id = e.position_id',
|
||||
'left'
|
||||
)
|
||||
|
||||
->join(
|
||||
'k_branches b',
|
||||
'b.id = e.branch_id',
|
||||
'left'
|
||||
)
|
||||
|
||||
->where('e.id',$id)
|
||||
->get()
|
||||
->row();
|
||||
|
||||
if (!$data) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message' => 'Data tidak ditemukan'
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->json([
|
||||
'status' => true,
|
||||
'data' => $data
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// STORE
|
||||
// =========================================================
|
||||
public function store()
|
||||
{
|
||||
try {
|
||||
|
||||
if (empty(trim($this->input->post('full_name')))) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message'=> 'Nama wajib diisi'
|
||||
]);
|
||||
}
|
||||
|
||||
if (empty($this->input->post('join_date'))) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message'=> 'Tanggal masuk wajib diisi'
|
||||
]);
|
||||
}
|
||||
|
||||
$employee_code = $this->generateEmployeeCode();
|
||||
|
||||
$photo = $this->uploadPhoto();
|
||||
|
||||
$data = $this->prepareData();
|
||||
|
||||
$data['employee_code'] = $employee_code;
|
||||
$data['photo'] = $photo;
|
||||
|
||||
$this->db->insert('k_employees',$data);
|
||||
|
||||
return $this->json([
|
||||
'status' => true,
|
||||
'message' => 'Berhasil simpan data'
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// UPDATE
|
||||
// =========================================================
|
||||
public function update($id = null)
|
||||
{
|
||||
try {
|
||||
|
||||
$employee = $this->db
|
||||
->get_where('k_employees',['id'=>$id])
|
||||
->row();
|
||||
|
||||
if (!$employee) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message' => 'Data tidak ditemukan'
|
||||
]);
|
||||
}
|
||||
|
||||
$data = $this->prepareData();
|
||||
|
||||
if (!empty($_FILES['photo_file']['name'])) {
|
||||
|
||||
$photo = $this->uploadPhoto();
|
||||
|
||||
if (
|
||||
!empty($employee->photo)
|
||||
&&
|
||||
file_exists(FCPATH . $employee->photo)
|
||||
) {
|
||||
unlink(FCPATH . $employee->photo);
|
||||
}
|
||||
|
||||
$data['photo'] = $photo;
|
||||
}
|
||||
|
||||
$this->db
|
||||
->where('id',$id)
|
||||
->update('k_employees',$data);
|
||||
|
||||
return $this->json([
|
||||
'status' => true,
|
||||
'message' => 'Berhasil update data'
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// DELETE
|
||||
// =========================================================
|
||||
public function delete($id = null)
|
||||
{
|
||||
try {
|
||||
|
||||
$employee = $this->db
|
||||
->get_where('k_employees',['id'=>$id])
|
||||
->row();
|
||||
|
||||
if (!$employee) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message' => 'Data tidak ditemukan'
|
||||
]);
|
||||
}
|
||||
|
||||
if (
|
||||
!empty($employee->photo)
|
||||
&&
|
||||
file_exists(FCPATH . $employee->photo)
|
||||
) {
|
||||
unlink(FCPATH . $employee->photo);
|
||||
}
|
||||
|
||||
$this->db->delete('k_employees',[
|
||||
'id'=>$id
|
||||
]);
|
||||
|
||||
return $this->json([
|
||||
'status' => true,
|
||||
'message' => 'Berhasil hapus data'
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
return $this->json([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// GENERATE CODE
|
||||
// =========================================================
|
||||
private function generateEmployeeCode()
|
||||
{
|
||||
$last = $this->db
|
||||
->order_by('id','DESC')
|
||||
->get('k_employees')
|
||||
->row();
|
||||
|
||||
$number = $last ? $last->id + 1 : 1;
|
||||
|
||||
return 'RJN-' . str_pad($number,5,'0',STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// UPLOAD PHOTO
|
||||
// =========================================================
|
||||
private function uploadPhoto()
|
||||
{
|
||||
if (empty($_FILES['photo_file']['name'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$path = FCPATH . 'uploads/karyawan/';
|
||||
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path,0777,true);
|
||||
}
|
||||
|
||||
$config['upload_path'] = './uploads/karyawan/';
|
||||
$config['allowed_types'] = 'jpg|jpeg|png|webp';
|
||||
$config['max_size'] = 2048;
|
||||
$config['encrypt_name'] = true;
|
||||
|
||||
$this->load->library('upload',$config);
|
||||
|
||||
if (!$this->upload->do_upload('photo_file')) {
|
||||
|
||||
throw new Exception(
|
||||
strip_tags(
|
||||
$this->upload->display_errors()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$upload = $this->upload->data();
|
||||
|
||||
return 'uploads/karyawan/' . $upload['file_name'];
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// PREPARE DATA
|
||||
// =========================================================
|
||||
private function prepareData()
|
||||
{
|
||||
return [
|
||||
|
||||
'nik' => trim($this->input->post('nik')),
|
||||
|
||||
'full_name' => trim(
|
||||
$this->input->post('full_name')
|
||||
),
|
||||
|
||||
'gender' => $this->input->post('gender'),
|
||||
|
||||
'birth_place' => trim(
|
||||
$this->input->post('birth_place')
|
||||
),
|
||||
|
||||
'birth_date' => $this->input->post('birth_date'),
|
||||
|
||||
'phone' => trim(
|
||||
$this->input->post('phone')
|
||||
),
|
||||
|
||||
'email' => trim(
|
||||
$this->input->post('email')
|
||||
),
|
||||
|
||||
'address' => trim(
|
||||
$this->input->post('address')
|
||||
),
|
||||
|
||||
'join_date' => $this->input->post('join_date'),
|
||||
|
||||
'resign_date' => $this->input->post('resign_date'),
|
||||
|
||||
'employment_status' => $this->input->post('employment_status'),
|
||||
|
||||
'marital_status' => $this->input->post('marital_status'),
|
||||
|
||||
'religion' => trim(
|
||||
$this->input->post('religion')
|
||||
),
|
||||
|
||||
'department_id' => $this->input->post('department_id'),
|
||||
|
||||
'position_id' => $this->input->post('position_id'),
|
||||
|
||||
'branch_id' => $this->input->post('branch_id'),
|
||||
|
||||
'basic_salary' => $this->input->post('basic_salary') ?: 0,
|
||||
|
||||
'bank_name' => trim(
|
||||
$this->input->post('bank_name')
|
||||
),
|
||||
|
||||
'bank_account_number' => trim(
|
||||
$this->input->post('bank_account_number')
|
||||
),
|
||||
|
||||
'bank_account_name' => trim(
|
||||
$this->input->post('bank_account_name')
|
||||
),
|
||||
|
||||
'bpjs_kesehatan_number' => trim(
|
||||
$this->input->post('bpjs_kesehatan_number')
|
||||
),
|
||||
|
||||
'bpjs_ketenagakerjaan_number' => trim(
|
||||
$this->input->post('bpjs_ketenagakerjaan_number')
|
||||
),
|
||||
|
||||
'fingerprint_user_id' => trim(
|
||||
$this->input->post('fingerprint_user_id')
|
||||
),
|
||||
|
||||
'is_active' => $this->input->post('is_active') ?: 1
|
||||
];
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// JSON
|
||||
// =========================================================
|
||||
private function json($data)
|
||||
{
|
||||
return $this->output
|
||||
->set_content_type('application/json')
|
||||
->set_output(json_encode($data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Generateinvoice extends CI_Controller {
|
||||
|
||||
public function generate($invoice_id)
|
||||
{
|
||||
// ❗ WAJIB: hindari output lain sebelum PDF
|
||||
ob_end_clean();
|
||||
|
||||
// =========================
|
||||
// 🔥 AMBIL DATA PERUSAHAAN
|
||||
// =========================
|
||||
$invp = $this->db->get('pengaturan')->row_array(); // 🔥 FIX: tidak pakai GET server_id
|
||||
|
||||
if(!$invp){
|
||||
show_error('Data perusahaan tidak ditemukan');
|
||||
}
|
||||
|
||||
$nama = $invp['nama_perusahaan'];
|
||||
$alamat = $invp['alamat_perusahaan'];
|
||||
$telepon = $invp['telepon_perusahaan'];
|
||||
$Keterangan = $invp['catatan_perusahaan'];
|
||||
$Pembuat = $invp['nama_bendahara'];
|
||||
$logo = base_url('uploads/img/logo-ljn.png');
|
||||
|
||||
// =========================
|
||||
// 🔥 GET INVOICE + CUSTOMER
|
||||
// =========================
|
||||
$invi = $this->db->select('invoices.*, customers.nama, customers.alamat, customers.telp')
|
||||
->from('invoices')
|
||||
->join('customers', 'customers.id = invoices.customer_id', 'left')
|
||||
->where('invoices.id', $invoice_id)
|
||||
->get()
|
||||
->row_array();
|
||||
|
||||
// =========================
|
||||
// VALIDASI
|
||||
// =========================
|
||||
if(!$invi){
|
||||
show_error('Invoice tidak ditemukan');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// MAPPING DATA
|
||||
// =========================
|
||||
$customerAddress = $invi['alamat'] ?? '-';
|
||||
$customerName = $invi['nama'] ?? '-';
|
||||
$customerNumber = $invi['telp'] ?? '-';
|
||||
|
||||
$invoiceNumber = $invi['no_invoice'] ?? '-';
|
||||
$invoiceDate = $invi['tanggal'] ?? '-'; // 🔥 sesuaikan field kamu
|
||||
$invoiceLimit = $invi['jatuh_tempo'] ?? '-'; // 🔥 sesuaikan juga
|
||||
|
||||
// =========================
|
||||
// 🔥 DETAIL ITEM
|
||||
// =========================
|
||||
$header = ['No','Tanggal','Item','Deskripsi','Qty','Harga', 'Subtotal'];
|
||||
$data = [];
|
||||
|
||||
// 🔥 NOTE: sesuaikan tabel kamu (invoice_details / invoice_list)
|
||||
// $detail = $this->db->get_where('invoice_details', [
|
||||
// 'invoice_id' => $invoice_id
|
||||
// ])->result_array();
|
||||
|
||||
$detail = $this->db
|
||||
->where('invoice_id', $invoice_id)
|
||||
->order_by('tanggal', 'ASC')
|
||||
->get('invoice_details')
|
||||
->result_array();
|
||||
|
||||
$no = 1;
|
||||
foreach($detail as $d){
|
||||
$data[] = [
|
||||
$no++,
|
||||
$d['tanggal'],
|
||||
$d['nama_item'],
|
||||
$d['keterangan'],
|
||||
$d['qty'],
|
||||
number_format($d['harga']),
|
||||
number_format($d['subtotal'])
|
||||
];
|
||||
}
|
||||
|
||||
// =========================
|
||||
// 🔥 TOTAL
|
||||
// =========================
|
||||
$total = (float)$invi['total'];
|
||||
|
||||
$this->db->select_sum('sisa_piutang');
|
||||
$this->db->where('customer_id', $invi['customer_id']);
|
||||
$this->db->where('status !=', 'paid');
|
||||
$this->db->where('id !=', $invoice_id); // exclude invoice sekarang
|
||||
|
||||
$tunggakan = $this->db->get('invoices')->row()->sisa_piutang ?? 0;
|
||||
|
||||
// Ngambil Data Tunggakan bulan lalu jika ada.
|
||||
$keteranganlain = 'Akumulasi Tunggakan Invoice Bulan Lalu';
|
||||
$nom_lainnya = $tunggakan;
|
||||
|
||||
$subtotal = number_format($total);
|
||||
$lainnya = number_format($nom_lainnya);
|
||||
$totalAmount = number_format($total + $nom_lainnya);
|
||||
$terbilang = trim($this->terbilang($total + $nom_lainnya)).' rupiah';
|
||||
|
||||
$filename = 'INV-'.$customerName.'-'.$invoiceNumber.'.pdf';
|
||||
|
||||
// =========================
|
||||
// 🔥 LOAD FPDF
|
||||
// =========================
|
||||
require_once(APPPATH.'third_party/fpdf/fpdf.php');
|
||||
require_once(APPPATH.'libraries/PDF_Invoice.php');
|
||||
|
||||
$pdf = new PDF();
|
||||
|
||||
// 🔥 FIX PATH LOGO (WAJIB)
|
||||
$logo_path = FCPATH.'img/user/'.$logo;
|
||||
if(!file_exists($logo_path)){
|
||||
$logo_path = ''; // biar gak error kalau logo tidak ada
|
||||
}
|
||||
|
||||
$pdf->setHeaderData($nama, $alamat, $telepon, $logo);
|
||||
$pdf->AddPage();
|
||||
$pdf->SetFont('Arial','',12);
|
||||
|
||||
$pdf->CustomerDetails(
|
||||
$customerName,
|
||||
$customerAddress,
|
||||
$invoiceNumber,
|
||||
$invoiceDate,
|
||||
$customerNumber,
|
||||
$invoiceLimit
|
||||
);
|
||||
|
||||
$pdf->InvoiceTable($header, $data);
|
||||
$pdf->Total($subtotal,$lainnya,$totalAmount,$terbilang,$keteranganlain);
|
||||
$pdf->Keterangan($Keterangan);
|
||||
$pdf->Pembuat($Pembuat);
|
||||
|
||||
// =========================
|
||||
// 🔥 OUTPUT LANGSUNG (TANPA SIMPAN)
|
||||
// =========================
|
||||
$pdf->Output('I', $filename);
|
||||
|
||||
|
||||
// =========================
|
||||
// LOG ACTIVITY
|
||||
// =========================
|
||||
log_activity(
|
||||
'invoice',
|
||||
'generate',
|
||||
'Generate invoice #' . $invoiceNumber . ' untuk ' . $customerName,
|
||||
'success'
|
||||
);
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// 🔥 TERBILANG
|
||||
// =========================
|
||||
private function terbilang($angka)
|
||||
{
|
||||
$angka = abs($angka);
|
||||
$baca = ["", "satu", "dua", "tiga", "empat", "lima", "enam", "tujuh", "delapan", "sembilan", "sepuluh", "sebelas"];
|
||||
|
||||
if ($angka < 12) {
|
||||
return " " . $baca[$angka];
|
||||
} elseif ($angka < 20) {
|
||||
return $this->terbilang($angka - 10) . " belas";
|
||||
} elseif ($angka < 100) {
|
||||
return $this->terbilang(intval($angka / 10)) . " puluh" . $this->terbilang($angka % 10);
|
||||
} elseif ($angka < 200) {
|
||||
return " seratus" . $this->terbilang($angka - 100);
|
||||
} elseif ($angka < 1000) {
|
||||
return $this->terbilang(intval($angka / 100)) . " ratus" . $this->terbilang($angka % 100);
|
||||
} elseif ($angka < 2000) {
|
||||
return " seribu" . $this->terbilang($angka - 1000);
|
||||
} elseif ($angka < 1000000) {
|
||||
return $this->terbilang(intval($angka / 1000)) . " ribu" . $this->terbilang($angka % 1000);
|
||||
} elseif ($angka < 1000000000) {
|
||||
return $this->terbilang(intval($angka / 1000000)) . " juta" . $this->terbilang($angka % 1000000);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,768 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Generateschedule extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->database();
|
||||
|
||||
date_default_timezone_set('Asia/Jakarta');
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// INDEX
|
||||
// =====================================================
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
"active_menu" => "generate_schedule"
|
||||
];
|
||||
|
||||
// ============================================
|
||||
// POSITIONS
|
||||
// ============================================
|
||||
$data['positions'] = $this->db
|
||||
->where('is_active',1)
|
||||
->order_by('position_name','ASC')
|
||||
->get('k_positions')
|
||||
->result();
|
||||
|
||||
// ============================================
|
||||
// SHIFTS
|
||||
// ============================================
|
||||
$data['shifts'] = $this->db
|
||||
->order_by('shift_code','ASC')
|
||||
->get('k_shifts')
|
||||
->result();
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('employees/generate_schedule', $data);
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// CALENDAR DATA
|
||||
// =====================================================
|
||||
public function calendar_data()
|
||||
{
|
||||
$month = (int)$this->input->get('month');
|
||||
$year = (int)$this->input->get('year');
|
||||
|
||||
if(empty($month)){
|
||||
$month = date('n');
|
||||
}
|
||||
|
||||
if(empty($year)){
|
||||
$year = date('Y');
|
||||
}
|
||||
|
||||
$firstDate = $year . '-'
|
||||
. str_pad($month,2,'0',STR_PAD_LEFT)
|
||||
. '-01';
|
||||
|
||||
// ============================================
|
||||
// START MONDAY
|
||||
// ============================================
|
||||
$startDate = date(
|
||||
'Y-m-d',
|
||||
strtotime('monday this week', strtotime($firstDate))
|
||||
);
|
||||
|
||||
if(date('N', strtotime($firstDate)) == 1){
|
||||
$startDate = $firstDate;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// END SUNDAY
|
||||
// ============================================
|
||||
$lastDate = date(
|
||||
'Y-m-t',
|
||||
strtotime($firstDate)
|
||||
);
|
||||
|
||||
$endDate = date(
|
||||
'Y-m-d',
|
||||
strtotime('sunday this week', strtotime($lastDate))
|
||||
);
|
||||
|
||||
$days = [];
|
||||
|
||||
$current = strtotime($startDate);
|
||||
$end = strtotime($endDate);
|
||||
|
||||
while($current <= $end){
|
||||
|
||||
$date = date('Y-m-d', $current);
|
||||
|
||||
// ========================================
|
||||
// GET SCHEDULE GROUP BY SHIFT
|
||||
// ========================================
|
||||
$this->db->select('
|
||||
sh.id as shift_id,
|
||||
sh.shift_name,
|
||||
|
||||
p.position_name,
|
||||
|
||||
COUNT(s.id) as total_employee
|
||||
');
|
||||
|
||||
$this->db->from('k_employee_shift_schedules s');
|
||||
|
||||
$this->db->join(
|
||||
'k_employees e',
|
||||
'e.id = s.employee_id',
|
||||
'left'
|
||||
);
|
||||
|
||||
$this->db->join(
|
||||
'k_positions p',
|
||||
'p.id = e.position_id',
|
||||
'left'
|
||||
);
|
||||
|
||||
$this->db->join(
|
||||
'k_shifts sh',
|
||||
'sh.id = s.shift_id',
|
||||
'left'
|
||||
);
|
||||
|
||||
$this->db->where('DATE(s.start_datetime)', $date);
|
||||
|
||||
// ========================================
|
||||
// GROUPING
|
||||
// ========================================
|
||||
$this->db->group_by('sh.id');
|
||||
$this->db->group_by('p.id');
|
||||
|
||||
$this->db->order_by('sh.checkin_time','ASC');
|
||||
$this->db->order_by('p.position_name','ASC');
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
// ========================================
|
||||
// FORMAT GROUPED
|
||||
// ========================================
|
||||
$grouped = [];
|
||||
|
||||
if($rows){
|
||||
|
||||
foreach($rows as $r){
|
||||
|
||||
$shiftId = $r->shift_id ?: 0;
|
||||
|
||||
if(!isset($grouped[$shiftId])){
|
||||
|
||||
$grouped[$shiftId] = [
|
||||
|
||||
'shift_id' => $r->shift_id,
|
||||
|
||||
'shift_name' => $r->shift_name ?: '-',
|
||||
|
||||
'positions' => []
|
||||
];
|
||||
}
|
||||
|
||||
$grouped[$shiftId]['positions'][] = [
|
||||
|
||||
'position_name' => $r->position_name ?: '-',
|
||||
|
||||
'total' => (int)$r->total_employee
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$days[] = [
|
||||
|
||||
'date' => date('d', strtotime($date)),
|
||||
|
||||
'month' => date('M', strtotime($date)),
|
||||
|
||||
'day_name' => $this->translateDay(
|
||||
date('l', strtotime($date))
|
||||
),
|
||||
|
||||
'full_date' => tanggal_indo($date),
|
||||
|
||||
'full_date_raw' => $date,
|
||||
|
||||
'is_current_month' => (
|
||||
date('m', strtotime($date))
|
||||
==
|
||||
str_pad($month,2,'0',STR_PAD_LEFT)
|
||||
),
|
||||
|
||||
'shifts' => array_values($grouped)
|
||||
];
|
||||
|
||||
$current = strtotime('+1 day', $current);
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'days' => $days
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// GET EMPLOYEE
|
||||
// =====================================================
|
||||
public function get_employees()
|
||||
{
|
||||
$position_id = $this->input->get('position_id');
|
||||
|
||||
$this->db->select('
|
||||
e.id,
|
||||
e.full_name,
|
||||
e.fingerprint_user_id,
|
||||
|
||||
p.position_name
|
||||
');
|
||||
|
||||
$this->db->from('k_employees e');
|
||||
|
||||
$this->db->join(
|
||||
'k_positions p',
|
||||
'p.id=e.position_id',
|
||||
'left'
|
||||
);
|
||||
|
||||
$this->db->where('e.is_active',1);
|
||||
|
||||
if(!empty($position_id)){
|
||||
$this->db->where('e.position_id',$position_id);
|
||||
}
|
||||
|
||||
$this->db->order_by('e.full_name','ASC');
|
||||
|
||||
$employees = $this->db->get()->result();
|
||||
|
||||
echo json_encode([
|
||||
'data' => $employees
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// SAVE MANUAL SCHEDULE
|
||||
// =====================================================
|
||||
public function save_manual_schedule()
|
||||
{
|
||||
try{
|
||||
|
||||
$employee_ids = $this->input->post('employee_ids');
|
||||
|
||||
$schedule_date = $this->input->post('schedule_date');
|
||||
|
||||
$shift_id = $this->input->post('shift_id');
|
||||
|
||||
// ============================================
|
||||
// VALIDASI
|
||||
// ============================================
|
||||
if(empty($employee_ids)){
|
||||
throw new Exception('Employee belum dipilih');
|
||||
}
|
||||
|
||||
if(empty($schedule_date)){
|
||||
throw new Exception('Tanggal wajib diisi');
|
||||
}
|
||||
|
||||
if(empty($shift_id)){
|
||||
throw new Exception('Shift wajib dipilih');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// GET SHIFT
|
||||
// ============================================
|
||||
$shift = $this->db
|
||||
->where('id', $shift_id)
|
||||
->get('k_shifts')
|
||||
->row();
|
||||
|
||||
if(!$shift){
|
||||
throw new Exception('Shift tidak ditemukan');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// BUILD START DATETIME
|
||||
// ============================================
|
||||
$start_datetime = date(
|
||||
'Y-m-d H:i:s',
|
||||
strtotime(
|
||||
$schedule_date . ' ' . $shift->checkin_time
|
||||
)
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// BUILD END DATETIME
|
||||
// ============================================
|
||||
$end_datetime = date(
|
||||
'Y-m-d H:i:s',
|
||||
strtotime(
|
||||
$schedule_date . ' ' . $shift->checkout_time
|
||||
)
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// JIKA SHIFT NYEBRANG HARI
|
||||
// ============================================
|
||||
$is_cross_day = 0;
|
||||
|
||||
if(
|
||||
strtotime($shift->checkout_time)
|
||||
<=
|
||||
strtotime($shift->checkin_time)
|
||||
){
|
||||
|
||||
$end_datetime = date(
|
||||
'Y-m-d H:i:s',
|
||||
strtotime('+1 day', strtotime($end_datetime))
|
||||
);
|
||||
|
||||
$is_cross_day = 1;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// HITUNG TOTAL JAM KERJA
|
||||
// ============================================
|
||||
$work_hours = (
|
||||
strtotime($end_datetime)
|
||||
-
|
||||
strtotime($start_datetime)
|
||||
) / 3600;
|
||||
|
||||
// ============================================
|
||||
// LOOP EMPLOYEE
|
||||
// ============================================
|
||||
foreach($employee_ids as $employee_id){
|
||||
|
||||
// ========================================
|
||||
// CHECK EXIST
|
||||
// ========================================
|
||||
$exists = $this->db
|
||||
->where('employee_id', $employee_id)
|
||||
->where('schedule_date', $schedule_date)
|
||||
->get('k_employee_shift_schedules')
|
||||
->row();
|
||||
|
||||
// ========================================
|
||||
// DATA SAVE
|
||||
// ========================================
|
||||
$saveData = [
|
||||
|
||||
'employee_id' => $employee_id,
|
||||
|
||||
'shift_id' => $shift_id,
|
||||
|
||||
'start_datetime' => $start_datetime,
|
||||
|
||||
'end_datetime' => $end_datetime,
|
||||
|
||||
'work_hours' => $work_hours,
|
||||
|
||||
'is_cross_day' => $is_cross_day,
|
||||
|
||||
'schedule_source' => 'manual',
|
||||
|
||||
'notes' => 'manual planner',
|
||||
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
// ========================================
|
||||
// UPDATE
|
||||
// ========================================
|
||||
if($exists){
|
||||
|
||||
$this->db
|
||||
->where('id', $exists->id)
|
||||
->update(
|
||||
'k_employee_shift_schedules',
|
||||
$saveData
|
||||
);
|
||||
|
||||
// ========================================
|
||||
// INSERT
|
||||
// ========================================
|
||||
} else {
|
||||
|
||||
$saveData['created_at'] = date('Y-m-d H:i:s');
|
||||
|
||||
$this->db->insert(
|
||||
'k_employee_shift_schedules',
|
||||
$saveData
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Jadwal berhasil disimpan'
|
||||
]);
|
||||
|
||||
} catch(Exception $e){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// TRANSLATE DAY
|
||||
// =====================================================
|
||||
private function translateDay($day)
|
||||
{
|
||||
$days = [
|
||||
'Sunday' => 'Minggu',
|
||||
'Monday' => 'Senin',
|
||||
'Tuesday' => 'Selasa',
|
||||
'Wednesday' => 'Rabu',
|
||||
'Thursday' => 'Kamis',
|
||||
'Friday' => 'Jumat',
|
||||
'Saturday' => 'Sabtu'
|
||||
];
|
||||
|
||||
return isset($days[$day])
|
||||
? $days[$day]
|
||||
: $day;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// DETAIL SCHEDULE
|
||||
// =====================================================
|
||||
public function detail_schedule()
|
||||
{
|
||||
$schedule_date = $this->input->get('schedule_date');
|
||||
|
||||
if(empty($schedule_date)){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message'=> 'Tanggal wajib diisi',
|
||||
'data' => []
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// GET DATA
|
||||
// ============================================
|
||||
$this->db->select('
|
||||
s.id as schedule_id,
|
||||
|
||||
s.employee_id,
|
||||
s.shift_id,
|
||||
|
||||
s.start_datetime,
|
||||
s.end_datetime,
|
||||
|
||||
e.employee_code,
|
||||
e.full_name,
|
||||
e.fingerprint_user_id,
|
||||
|
||||
p.id as position_id,
|
||||
p.position_name,
|
||||
|
||||
sh.shift_name,
|
||||
sh.checkin_time,
|
||||
sh.checkout_time,
|
||||
sh.color
|
||||
');
|
||||
|
||||
$this->db->from('k_employee_shift_schedules s');
|
||||
|
||||
$this->db->join(
|
||||
'k_employees e',
|
||||
'e.id=s.employee_id',
|
||||
'left'
|
||||
);
|
||||
|
||||
$this->db->join(
|
||||
'k_positions p',
|
||||
'p.id=e.position_id',
|
||||
'left'
|
||||
);
|
||||
|
||||
$this->db->join(
|
||||
'k_shifts sh',
|
||||
'sh.id=s.shift_id',
|
||||
'left'
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// FILTER DATE
|
||||
// ============================================
|
||||
$this->db->where(
|
||||
'DATE(s.start_datetime)',
|
||||
$schedule_date
|
||||
);
|
||||
|
||||
$this->db->order_by('p.position_name','ASC');
|
||||
|
||||
$this->db->order_by('e.full_name','ASC');
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
// ============================================
|
||||
// GROUP POSITION
|
||||
// ============================================
|
||||
$grouped = [];
|
||||
|
||||
if($rows){
|
||||
|
||||
foreach($rows as $r){
|
||||
|
||||
$position_id = $r->position_id ?: 0;
|
||||
|
||||
// ====================================
|
||||
// CREATE GROUP
|
||||
// ====================================
|
||||
if(!isset($grouped[$position_id])){
|
||||
|
||||
$grouped[$position_id] = [
|
||||
|
||||
'position_id' => $r->position_id,
|
||||
|
||||
'position_name' => $r->position_name ?: '-',
|
||||
|
||||
'employees' => []
|
||||
];
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// EMPLOYEE
|
||||
// ====================================
|
||||
$grouped[$position_id]['employees'][] = [
|
||||
|
||||
'schedule_id' => $r->schedule_id,
|
||||
|
||||
'employee_id' => $r->employee_id,
|
||||
|
||||
'full_name' => $r->full_name,
|
||||
|
||||
'employee_code' => $r->employee_code,
|
||||
|
||||
'fingerprint_user_id' => $r->fingerprint_user_id,
|
||||
|
||||
'shift_id' => $r->shift_id,
|
||||
|
||||
'shift_name' => $r->shift_name,
|
||||
|
||||
'checkin' => $r->checkin_time
|
||||
? date(
|
||||
'H:i',
|
||||
strtotime($r->checkin_time)
|
||||
)
|
||||
: '-',
|
||||
|
||||
'checkout' => $r->checkout_time
|
||||
? date(
|
||||
'H:i',
|
||||
strtotime($r->checkout_time)
|
||||
)
|
||||
: '-',
|
||||
|
||||
'start_datetime' => $r->start_datetime,
|
||||
|
||||
'end_datetime' => $r->end_datetime,
|
||||
|
||||
'color' => $r->color
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'data' => array_values($grouped)
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// UPDATE SCHEDULE SHIFT
|
||||
// =====================================================
|
||||
public function update_schedule_shift()
|
||||
{
|
||||
try{
|
||||
|
||||
$schedule_id = $this->input->post('schedule_id');
|
||||
|
||||
$shift_id = $this->input->post('shift_id');
|
||||
|
||||
// ============================================
|
||||
// VALIDASI
|
||||
// ============================================
|
||||
if(empty($schedule_id)){
|
||||
throw new Exception('Schedule ID kosong');
|
||||
}
|
||||
|
||||
if(empty($shift_id)){
|
||||
throw new Exception('Shift wajib dipilih');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// CHECK SCHEDULE
|
||||
// ============================================
|
||||
$schedule = $this->db
|
||||
->where('id', $schedule_id)
|
||||
->get('k_employee_shift_schedules')
|
||||
->row();
|
||||
|
||||
if(!$schedule){
|
||||
throw new Exception('Schedule tidak ditemukan');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// CHECK SHIFT
|
||||
// ============================================
|
||||
$shift = $this->db
|
||||
->where('id', $shift_id)
|
||||
->get('k_shifts')
|
||||
->row();
|
||||
|
||||
if(!$shift){
|
||||
throw new Exception('Shift tidak ditemukan');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// AMBIL TANGGAL
|
||||
// ============================================
|
||||
$schedule_date = date(
|
||||
'Y-m-d',
|
||||
strtotime($schedule->start_datetime)
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// BUILD START DATETIME
|
||||
// ============================================
|
||||
$start_datetime = date(
|
||||
'Y-m-d H:i:s',
|
||||
strtotime(
|
||||
$schedule_date . ' ' . $shift->checkin_time
|
||||
)
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// BUILD END DATETIME
|
||||
// ============================================
|
||||
$end_datetime = date(
|
||||
'Y-m-d H:i:s',
|
||||
strtotime(
|
||||
$schedule_date . ' ' . $shift->checkout_time
|
||||
)
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// CROSS DAY
|
||||
// ============================================
|
||||
$is_cross_day = 0;
|
||||
|
||||
if(
|
||||
strtotime($shift->checkout_time)
|
||||
<=
|
||||
strtotime($shift->checkin_time)
|
||||
){
|
||||
|
||||
$end_datetime = date(
|
||||
'Y-m-d H:i:s',
|
||||
strtotime('+1 day', strtotime($end_datetime))
|
||||
);
|
||||
|
||||
$is_cross_day = 1;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// WORK HOURS
|
||||
// ============================================
|
||||
$work_hours = $shift->work_hours;
|
||||
|
||||
// ============================================
|
||||
// UPDATE
|
||||
// ============================================
|
||||
$this->db
|
||||
->where('id', $schedule_id)
|
||||
->update(
|
||||
'k_employee_shift_schedules',
|
||||
[
|
||||
|
||||
'shift_id' => $shift_id,
|
||||
|
||||
'start_datetime' => $start_datetime,
|
||||
|
||||
'end_datetime' => $end_datetime,
|
||||
|
||||
'work_hours' => $work_hours,
|
||||
|
||||
'is_cross_day' => $is_cross_day,
|
||||
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
]
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Shift berhasil diupdate'
|
||||
]);
|
||||
|
||||
} catch(Exception $e){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =====================================================
|
||||
// DELETE SCHEDULE
|
||||
// =====================================================
|
||||
public function delete_schedule()
|
||||
{
|
||||
try{
|
||||
|
||||
$schedule_id = $this->input->post('schedule_id');
|
||||
|
||||
// ============================================
|
||||
// VALIDASI
|
||||
// ============================================
|
||||
if(empty($schedule_id)){
|
||||
throw new Exception('Schedule ID kosong');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// CHECK DATA
|
||||
// ============================================
|
||||
$schedule = $this->db
|
||||
->where('id', $schedule_id)
|
||||
->get('k_employee_shift_schedules')
|
||||
->row();
|
||||
|
||||
if(!$schedule){
|
||||
throw new Exception('Schedule tidak ditemukan');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// DELETE
|
||||
// ============================================
|
||||
$this->db
|
||||
->where('id', $schedule_id)
|
||||
->delete('k_employee_shift_schedules');
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Schedule berhasil dihapus'
|
||||
]);
|
||||
|
||||
} catch(Exception $e){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Holidays extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->database();
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// VIEW
|
||||
// =========================================
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
"active_menu" => "holidays"
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('employees/holidays');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// GET DATA
|
||||
// =========================================
|
||||
public function get_data()
|
||||
{
|
||||
$data = $this->db
|
||||
->order_by('holiday_date','DESC')
|
||||
->get('k_holidays')
|
||||
->result();
|
||||
|
||||
$rows = [];
|
||||
|
||||
$no = 1;
|
||||
|
||||
foreach($data as $d){
|
||||
|
||||
$rows[] = [
|
||||
$no++,
|
||||
date('d M Y', strtotime($d->holiday_date)),
|
||||
$d->holiday_name,
|
||||
$d->is_national == 1
|
||||
? '<span class="badge bg-success">Nasional</span>'
|
||||
: '<span class="badge bg-secondary">Perusahaan</span>',
|
||||
'
|
||||
<button class="btn btn-warning btn-sm btn-edit"
|
||||
data-id="'.$d->id.'">
|
||||
Edit
|
||||
</button>
|
||||
|
||||
<button class="btn btn-danger btn-sm btn-delete"
|
||||
data-id="'.$d->id.'">
|
||||
Delete
|
||||
</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'data' => $rows
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// DETAIL
|
||||
// =========================================
|
||||
public function detail($id)
|
||||
{
|
||||
$data = $this->db
|
||||
->get_where('k_holidays',['id'=>$id])
|
||||
->row();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// SAVE
|
||||
// =========================================
|
||||
public function save()
|
||||
{
|
||||
$holiday_date = $this->input->post('holiday_date');
|
||||
$holiday_name = $this->input->post('holiday_name');
|
||||
$is_national = $this->input->post('is_national');
|
||||
|
||||
$cek = $this->db
|
||||
->get_where('k_holidays',[
|
||||
'holiday_date' => $holiday_date
|
||||
])
|
||||
->row();
|
||||
|
||||
if($cek){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Tanggal holiday sudah ada'
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$insert = [
|
||||
'holiday_date' => $holiday_date,
|
||||
'holiday_name' => $holiday_name,
|
||||
'is_national' => $is_national
|
||||
];
|
||||
|
||||
$this->db->insert('k_holidays',$insert);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Holiday berhasil ditambahkan'
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// UPDATE
|
||||
// =========================================
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
$holiday_date = $this->input->post('holiday_date');
|
||||
$holiday_name = $this->input->post('holiday_name');
|
||||
$is_national = $this->input->post('is_national');
|
||||
|
||||
$cek = $this->db
|
||||
->where('holiday_date',$holiday_date)
|
||||
->where('id !=',$id)
|
||||
->get('k_holidays')
|
||||
->row();
|
||||
|
||||
if($cek){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Tanggal holiday sudah ada'
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$update = [
|
||||
'holiday_date' => $holiday_date,
|
||||
'holiday_name' => $holiday_name,
|
||||
'is_national' => $is_national
|
||||
];
|
||||
|
||||
$this->db
|
||||
->where('id',$id)
|
||||
->update('k_holidays',$update);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Holiday berhasil diupdate'
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// DELETE
|
||||
// =========================================
|
||||
public function delete($id)
|
||||
{
|
||||
$this->db
|
||||
->where('id',$id)
|
||||
->delete('k_holidays');
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Holiday berhasil dihapus'
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,795 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Items extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data = ["active_menu" => "items"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('items/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
public function draft_items()
|
||||
{
|
||||
$data = ["active_menu" => "draft_items"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('items/draft_items');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET DATA (FIX)
|
||||
// =========================
|
||||
public function get_data()
|
||||
{
|
||||
$status = $this->input->get('s') ?? 'all';
|
||||
|
||||
$allowed = ['draft','active','all'];
|
||||
if (!in_array($status, $allowed)) {
|
||||
$status = 'all';
|
||||
}
|
||||
|
||||
$this->db->select('
|
||||
items.id,
|
||||
items.nama_barang,
|
||||
items.kode_detail,
|
||||
items.harga_beli,
|
||||
items.harga_jual,
|
||||
items.tanggal_pembelian,
|
||||
items.created_at,
|
||||
items.stok,
|
||||
items.status,
|
||||
items.kode_id,
|
||||
(
|
||||
SELECT GROUP_CONCAT(DISTINCT w.nama SEPARATOR ", ")
|
||||
FROM stock_logs sl
|
||||
LEFT JOIN warehouses w ON sl.warehouse_id = w.id
|
||||
WHERE sl.item_id = items.id
|
||||
) as gudang
|
||||
');
|
||||
|
||||
if ($status !== 'all') {
|
||||
$this->db->where('items.status', $status);
|
||||
}
|
||||
|
||||
// urutan custom
|
||||
$this->db->order_by('(items.stok = 0)', 'ASC', false);
|
||||
$this->db->order_by('items.tanggal_pembelian', 'ASC');
|
||||
|
||||
$this->db->from('items');
|
||||
|
||||
$data = $this->db->get()->result();
|
||||
|
||||
// $this->db->select('
|
||||
// items.id,
|
||||
// items.nama_barang,
|
||||
// items.kode_detail,
|
||||
// items.harga_beli,
|
||||
// items.harga_jual,
|
||||
// items.tanggal_pembelian,
|
||||
// items.created_at,
|
||||
// items.stok,
|
||||
// items.status,
|
||||
// items.kode_id,
|
||||
// (
|
||||
// SELECT GROUP_CONCAT(DISTINCT w.nama SEPARATOR ", ")
|
||||
// FROM stock_logs sl
|
||||
// LEFT JOIN warehouses w ON sl.warehouse_id = w.id
|
||||
// WHERE sl.item_id = items.id
|
||||
// ) as gudang
|
||||
// ');
|
||||
|
||||
// if ($status !== 'all') {
|
||||
// $this->db->where('items.status', $status);
|
||||
// }
|
||||
|
||||
// // 🔥 filter utama per kode_id
|
||||
// $this->db->where("
|
||||
// (items.stok > 0)
|
||||
// OR
|
||||
// (
|
||||
// items.stok = 0
|
||||
// AND items.tanggal_pembelian = (
|
||||
// SELECT MAX(i2.tanggal_pembelian)
|
||||
// FROM items i2
|
||||
// WHERE i2.stok = 0
|
||||
// AND i2.kode_id = items.kode_id
|
||||
// )
|
||||
// )
|
||||
// ", null, false);
|
||||
|
||||
// // urutan
|
||||
// $this->db->order_by('items.stok = 0', 'ASC', false);
|
||||
// $this->db->order_by('items.tanggal_pembelian', 'ASC');
|
||||
|
||||
// $this->db->from('items');
|
||||
|
||||
// $data = $this->db->get()->result();
|
||||
|
||||
$result = [];
|
||||
$no = 1;
|
||||
|
||||
foreach($data as $row){
|
||||
|
||||
$btnDetail = '<button class="btn btn-info btn-sm btn-detail m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Detail</button>';
|
||||
$btnEdit = '<button class="btn btn-secondary btn-sm btn-editItem m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Edit</button>';
|
||||
$btnDelete = '<button class="btn btn-danger btn-sm btn-delete m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Delete</button>';
|
||||
|
||||
if($row->status == 'draft'){
|
||||
$btnPost = '<button class="btn btn-success btn-sm btn-updatePosting m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Posting</button>';
|
||||
$action = $btnDetail . $btnPost . $btnDelete;
|
||||
} else {
|
||||
if($this->session->userdata('role') == 'Admin') {
|
||||
$btnAdjust = '<button class="btn btn-warning btn-sm btn-adjust m-1" data-id="'.htmlspecialchars($row->id, ENT_QUOTES, 'UTF-8').'">Adjust</button>';
|
||||
} else {
|
||||
$btnAdjust = '';
|
||||
}
|
||||
$action = $btnDetail . $btnEdit . $btnAdjust . $btnDelete;
|
||||
}
|
||||
|
||||
$result[] = [
|
||||
$no++,
|
||||
$row->tanggal_pembelian,
|
||||
$row->kode_detail,
|
||||
$row->nama_barang,
|
||||
$row->gudang ?? '-',
|
||||
$row->stok,
|
||||
number_format($row->harga_beli ?? 0, 2),
|
||||
number_format($row->harga_jual ?? 0, 2),
|
||||
$row->created_at,
|
||||
$action
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode(["data"=>$result]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DETAIL
|
||||
// =========================
|
||||
public function detail_simple($id)
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->get_where('items',['id'=>$id])->row()
|
||||
);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DETAIL
|
||||
// =========================
|
||||
public function detail($id)
|
||||
{
|
||||
$item = $this->db->get_where('items',['id'=>$id])->row();
|
||||
|
||||
$logs = $this->db
|
||||
->select('stock_logs.*, warehouses.nama as gudang')
|
||||
->join('warehouses','warehouses.id = stock_logs.warehouse_id','left')
|
||||
->where('item_id',$id)
|
||||
->order_by('stock_logs.id','DESC')
|
||||
->get('stock_logs')
|
||||
->result();
|
||||
|
||||
echo json_encode([
|
||||
'item'=>$item,
|
||||
'logs'=>$logs
|
||||
]);
|
||||
}
|
||||
|
||||
public function get_accounts()
|
||||
{
|
||||
$data = $this->db
|
||||
->where_in('kode_akun', [101,102,201])
|
||||
->order_by('kode_akun','ASC')
|
||||
->get('accounts')
|
||||
->result();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
public function get_accounts_biaya()
|
||||
{
|
||||
$data = $this->db
|
||||
->where(['tipe' => 'expense', 'posisi'=> 'debit', 'kategori'=> 'laba_rugi'])
|
||||
->order_by('kode_akun','ASC')
|
||||
->get('accounts')
|
||||
->result();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// SAVE (FIX TOTAL)
|
||||
// =========================
|
||||
public function save()
|
||||
{
|
||||
$nama_barang = $this->input->post('nama_barang');
|
||||
$qty = (int)$this->input->post('qty');
|
||||
$harga_beli = (float)$this->input->post('harga_beli');
|
||||
$harga_jual = (float)$this->input->post('harga_jual');
|
||||
$warehouse_id = $this->input->post('warehouse_id');
|
||||
$account_kas = $this->input->post('account_kas');
|
||||
$kode_id = $this->input->post('kode_id');
|
||||
$tanggal_beli = $this->input->post('tanggal_beli');
|
||||
$status = $this->input->post('status');
|
||||
|
||||
// ================= VALIDASI =================
|
||||
if(!$nama_barang || $qty <= 0 || $harga_beli <= 0 || !$warehouse_id || !$account_kas){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Data tidak lengkap / tidak valid'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// ================= VALIDASI HARGA =================
|
||||
if($harga_beli > $harga_jual){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Harga beli tidak boleh lebih besar dari harga jual'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$kode = $this->db->get_where('kode_barang',['id'=>$kode_id])->row();
|
||||
|
||||
$tanggal_kode = date('dmy', strtotime($tanggal_beli));
|
||||
$kode_detail = $kode->kode_barang . '-' . $tanggal_kode;
|
||||
|
||||
$total = $qty * $harga_beli;
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
// ================= INSERT ITEM =================
|
||||
$this->db->insert('items',[
|
||||
'stok' =>$qty,
|
||||
'kode_detail' =>$kode_detail,
|
||||
'kode_id' =>$kode_id,
|
||||
'nama_barang' =>$nama_barang,
|
||||
'harga_beli' =>$harga_beli,
|
||||
'harga_jual' =>$harga_jual,
|
||||
'tanggal_pembelian' => $tanggal_beli,
|
||||
'status' => $status
|
||||
]);
|
||||
|
||||
$item_id = $this->db->insert_id();
|
||||
|
||||
// ================= STOCK MASUK =================
|
||||
$this->db->insert('stock_logs',[
|
||||
'item_id'=>$item_id,
|
||||
'warehouse_id'=>$warehouse_id,
|
||||
'qty'=>$qty,
|
||||
'tipe'=>'masuk',
|
||||
'keterangan'=>'Pembelian awal',
|
||||
'created_at'=>date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
// ================= JURNAL =================
|
||||
$no_ref = 'BLI-'.date('Ymd').'-'.$item_id;
|
||||
|
||||
$this->db->insert('journals',[
|
||||
'tanggal'=>$tanggal_beli,
|
||||
'no_ref'=>$no_ref,
|
||||
'ref_type'=> 'new_items',
|
||||
'ref_id'=>$item_id,
|
||||
'keterangan'=>'Pembelian '.$nama_barang,
|
||||
'created_by' => $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$jid = $this->db->insert_id();
|
||||
|
||||
// 🔥 Debit Persediaan
|
||||
$this->db->insert('journal_details',[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>21, // persediaan
|
||||
'debit'=>$total,
|
||||
'kredit'=>0
|
||||
]);
|
||||
|
||||
// 🔥 Kredit Kas (DINAMIS)
|
||||
$this->db->insert('journal_details',[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>$account_kas,
|
||||
'debit'=>0,
|
||||
'kredit'=>$total
|
||||
]);
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
// ================= CEK TRANSAKSI =================
|
||||
if ($this->db->trans_status() === FALSE){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Gagal simpan data'
|
||||
]);
|
||||
} else {
|
||||
|
||||
log_activity(
|
||||
'items',
|
||||
'create',
|
||||
'Menambahkan item: ' . $nama_barang,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status'=>true,
|
||||
'message'=>'Berhasil tambah item'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================
|
||||
// UPDATE (FIX AKUN)
|
||||
// =========================
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
$nama_barang = $this->input->post('nama_barang');
|
||||
$harga_baru = (float)$this->input->post('harga_beli');
|
||||
$harga_jual = (float)$this->input->post('harga_jual');
|
||||
|
||||
$item = $this->db->get_where('items',['id'=>$id])->row();
|
||||
|
||||
if(!$item){
|
||||
echo json_encode(['status'=>false,'message'=>'Item tidak ditemukan']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
$this->db->where('id',$id)->update('items',[
|
||||
'nama_barang'=>$nama_barang,
|
||||
'harga_beli'=>$harga_baru,
|
||||
'harga_jual'=>$harga_jual
|
||||
]);
|
||||
|
||||
if($item->harga_beli != $harga_baru){
|
||||
|
||||
$stok = $this->db->select('SUM(qty * IF(tipe="masuk",1,-1)) as stok')
|
||||
->where('item_id',$id)
|
||||
->get('stock_logs')
|
||||
->row()->stok ?? 0;
|
||||
|
||||
$selisih = ($harga_baru - $item->harga_beli) * $stok;
|
||||
|
||||
if($selisih != 0){
|
||||
|
||||
$this->db->insert('journals',[
|
||||
'tanggal'=>date('Y-m-d'),
|
||||
'no_ref'=>'ADJ-'.date('YmdHis').'-'.$id,
|
||||
'keterangan'=>'Penyesuaian harga '.$item->nama_barang,
|
||||
'created_by' => $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$jid = $this->db->insert_id();
|
||||
|
||||
if($selisih > 0){
|
||||
// 🔥 naik → pendapatan
|
||||
$this->db->insert_batch('journal_details',[
|
||||
[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>21,
|
||||
'debit'=>$selisih,
|
||||
'kredit'=>0
|
||||
],
|
||||
[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>65, // ✅ BENAR
|
||||
'debit'=>0,
|
||||
'kredit'=>$selisih
|
||||
]
|
||||
]);
|
||||
}else{
|
||||
// 🔥 turun → beban
|
||||
$this->db->insert_batch('journal_details',[
|
||||
[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>64, // ✅ BENAR
|
||||
'debit'=>abs($selisih),
|
||||
'kredit'=>0
|
||||
],
|
||||
[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>21,
|
||||
'debit'=>0,
|
||||
'kredit'=>abs($selisih)
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
log_activity(
|
||||
'items',
|
||||
'update',
|
||||
'Update item: ' . $nama_barang,
|
||||
'success'
|
||||
);
|
||||
|
||||
$this->update_item_stok($id);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Berhasil update + adjustment']);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
// cek item ada
|
||||
$item = $this->db->get_where('items',['id'=>$id])->row();
|
||||
|
||||
if(!$item){
|
||||
echo json_encode(['status'=>false,'message'=>'Item tidak ditemukan']);
|
||||
return;
|
||||
}
|
||||
|
||||
// cek ada transaksi stock
|
||||
$cekStock = $this->db->where('item_id',$id)->count_all_results('stock_logs');
|
||||
|
||||
if($cekStock > 1){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Tidak bisa dihapus, sudah ada transaksi stok'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
// hapus item
|
||||
$this->db->delete('stock_logs',['item_id'=>$id]);
|
||||
$this->db->delete('items',['id'=>$id]);
|
||||
|
||||
$j = $this->db->get_where('journals', [
|
||||
'ref_type'=>'new_items',
|
||||
'ref_id'=>$id
|
||||
])->result();
|
||||
|
||||
foreach($j as $row){
|
||||
$this->db->delete('journal_details', ['journal_id'=>$row->id]);
|
||||
$this->db->delete('journals', ['id'=>$row->id]);
|
||||
}
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
if ($this->db->trans_status() === FALSE){
|
||||
echo json_encode(['status'=>false,'message'=>'Gagal hapus']);
|
||||
} else {
|
||||
|
||||
log_activity(
|
||||
'items',
|
||||
'delete',
|
||||
'Hapus item ID: ' . $id,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Berhasil dihapus']);
|
||||
}
|
||||
}
|
||||
|
||||
public function posting()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
|
||||
if(!$id){
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'ID tidak valid'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// cek item ada
|
||||
$item = $this->db->get_where('items', ['id' => $id])->row();
|
||||
|
||||
if(!$item){
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Item tidak ditemukan'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// cegah double posting
|
||||
if($item->status == 'active'){
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Barang sudah diterima sebelumnya'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
// update status saja
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update('items', [
|
||||
'status' => 'active'
|
||||
]);
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
if ($this->db->trans_status() === FALSE){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Gagal memproses data'
|
||||
]);
|
||||
|
||||
} else {
|
||||
|
||||
// log aktivitas
|
||||
log_activity(
|
||||
'items',
|
||||
'posting',
|
||||
'Barang diterima | ID: '.$id.' | Nama: '.$item->nama_barang,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Barang sudah diterima dan stok siap digunakan'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================
|
||||
// KELUAR BARANG (FIX TANPA stok column)
|
||||
// =========================
|
||||
public function keluarkan()
|
||||
{
|
||||
$account_biaya = (int)$this->input->post('account_biaya');
|
||||
$tanggal_keluar = $this->input->post('tanggal_keluar');
|
||||
$warehouse_id_keluar = $this->input->post('warehouse_id_keluar');
|
||||
$barang_id = $this->input->post('barang_id');
|
||||
$qty_keluar = (int)$this->input->post('qty_keluar');
|
||||
$keterangan_keluar = $this->input->post('keterangan_keluar');
|
||||
|
||||
// =========================
|
||||
// VALIDASI
|
||||
// =========================
|
||||
if(!$barang_id || !$warehouse_id_keluar || $qty_keluar <= 0){
|
||||
echo json_encode(['status'=>false,'message'=>'Data tidak valid']);
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// CEK ITEM
|
||||
// =========================
|
||||
$item = $this->db->get_where('items',['id'=>$barang_id])->row();
|
||||
if(!$item){
|
||||
echo json_encode(['status'=>false,'message'=>'Item tidak ditemukan']);
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// HITUNG STOK
|
||||
// =========================
|
||||
$stok = $this->db->select('
|
||||
COALESCE(SUM(qty * IF(tipe="masuk",1,-1)),0) as stok
|
||||
')
|
||||
->where('item_id',$barang_id)
|
||||
->where('warehouse_id',$warehouse_id_keluar)
|
||||
->get('stock_logs')
|
||||
->row()->stok;
|
||||
|
||||
if($stok < $qty_keluar){
|
||||
echo json_encode(['status'=>false,'message'=>'Stok tidak cukup']);
|
||||
return;
|
||||
}
|
||||
|
||||
$nilai = $qty_keluar * (float)$item->harga_beli;
|
||||
|
||||
// =========================
|
||||
// TRANSACTION
|
||||
// =========================
|
||||
$this->db->trans_start();
|
||||
|
||||
// log keluar
|
||||
$this->db->insert('stock_logs',[
|
||||
'item_id'=>$barang_id,
|
||||
'warehouse_id'=>$warehouse_id_keluar,
|
||||
'qty'=>$qty_keluar,
|
||||
'tipe'=>'keluar',
|
||||
'keterangan'=>$keterangan_keluar
|
||||
]);
|
||||
|
||||
$stock_log_id = $this->db->insert_id();
|
||||
|
||||
// jurnal
|
||||
$this->db->insert('journals',[
|
||||
'tanggal'=>$tanggal_keluar,
|
||||
'no_ref'=>'GOUT-'.date('YmdHis').'-'.$barang_id,
|
||||
'keterangan'=>'Pengeluaran Barang '.$item->nama_barang . ' ( ' . $keterangan_keluar . ' )',
|
||||
'ref_type' =>'stock_logs',
|
||||
'ref_id' => $stock_log_id,
|
||||
'created_by' => $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$jid = $this->db->insert_id();
|
||||
|
||||
// Debit biaya / HPP
|
||||
$this->db->insert('journal_details',[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>$account_biaya,
|
||||
'debit'=>$nilai,
|
||||
'kredit'=>0
|
||||
]);
|
||||
|
||||
// Kredit persediaan
|
||||
$this->db->insert('journal_details',[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>21,
|
||||
'debit'=>0,
|
||||
'kredit'=>$nilai
|
||||
]);
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
// =========================
|
||||
// CEK TRANSACTION
|
||||
// =========================
|
||||
if (!$this->db->trans_status()) {
|
||||
echo json_encode(['status'=>false,'message'=>'Gagal proses']);
|
||||
return;
|
||||
}
|
||||
|
||||
log_activity(
|
||||
'items',
|
||||
'stock_out',
|
||||
'Keluar barang: ' . $item->nama_barang . ' qty: ' . $qty_keluar . ' ( ' . $keterangan_keluar . ' )',
|
||||
'success'
|
||||
);
|
||||
|
||||
$this->update_item_stok($barang_id);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Barang berhasil dikeluarkan']);
|
||||
}
|
||||
|
||||
public function list()
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->get('warehouses')->result()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function adjust()
|
||||
{
|
||||
$item_id = $this->input->post('item_id');
|
||||
$qty = (int)$this->input->post('qty');
|
||||
$warehouse_id = $this->input->post('warehouse_id');
|
||||
$ket = $this->input->post('keterangan');
|
||||
|
||||
if($qty == 0){
|
||||
echo json_encode(['status'=>false,'message'=>'Qty tidak boleh 0']);
|
||||
return;
|
||||
}
|
||||
|
||||
$item = $this->db->get_where('items',['id'=>$item_id])->row();
|
||||
|
||||
$nilai = abs($qty) * $item->harga_beli;
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
// 🔥 stock log
|
||||
$this->db->insert('stock_logs',[
|
||||
'item_id'=>$item_id,
|
||||
'warehouse_id'=>$warehouse_id,
|
||||
'qty'=>abs($qty),
|
||||
'tipe'=> $qty > 0 ? 'masuk' : 'keluar',
|
||||
'keterangan'=>'Adjustment: '.$ket
|
||||
]);
|
||||
|
||||
// 🔥 jurnal
|
||||
$this->db->insert('journals',[
|
||||
'tanggal'=>date('Y-m-d'),
|
||||
'no_ref'=>'ADJ-'.date('Ymd').'-'.$item_id,
|
||||
'keterangan'=>'Penyesuaian '.$item->nama_barang,
|
||||
'created_by' => $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$jid = $this->db->insert_id();
|
||||
|
||||
if($qty > 0){
|
||||
// stok naik
|
||||
$this->db->insert_batch('journal_details',[
|
||||
[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>21, // persediaan
|
||||
'debit'=>$nilai,
|
||||
'kredit'=>0
|
||||
],
|
||||
[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>65, // modal / selisih
|
||||
'debit'=>0,
|
||||
'kredit'=>$nilai
|
||||
]
|
||||
]);
|
||||
}else{
|
||||
// stok turun
|
||||
$this->db->insert_batch('journal_details',[
|
||||
[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>64,
|
||||
'debit'=>$nilai,
|
||||
'kredit'=>0
|
||||
],
|
||||
[
|
||||
'journal_id'=>$jid,
|
||||
'account_id'=>21,
|
||||
'debit'=>0,
|
||||
'kredit'=>$nilai
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
log_activity(
|
||||
'items',
|
||||
'adjust',
|
||||
'Adjustment item ID: ' . $item_id . ' qty: ' . $qty,
|
||||
'success'
|
||||
);
|
||||
|
||||
$this->update_item_stok($item_id);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Adjustment berhasil']);
|
||||
}
|
||||
|
||||
private function update_item_stok($item_id)
|
||||
{
|
||||
$stok = $this->db->query("
|
||||
SELECT COALESCE(SUM(qty * IF(tipe='masuk',1,-1)),0) as stok
|
||||
FROM stock_logs
|
||||
WHERE item_id = ?
|
||||
", [$item_id])->row()->stok;
|
||||
|
||||
$this->db->where('id', $item_id)
|
||||
->update('items', [
|
||||
'stok' => $stok
|
||||
]);
|
||||
}
|
||||
|
||||
public function get_items_by_wh_id($warehouse_id)
|
||||
{
|
||||
$this->db->select('
|
||||
items.id,
|
||||
items.nama_barang,
|
||||
items.harga_jual,
|
||||
items.kode_detail,
|
||||
COALESCE(SUM(
|
||||
stock_logs.qty * IF(stock_logs.tipe="masuk",1,-1)
|
||||
),0) as stok
|
||||
');
|
||||
$this->db->where('status', 'active');
|
||||
$this->db->from('items');
|
||||
|
||||
$this->db->join('stock_logs',
|
||||
'stock_logs.item_id = items.id
|
||||
AND stock_logs.warehouse_id = '.$this->db->escape($warehouse_id),
|
||||
'left');
|
||||
|
||||
$this->db->group_by('items.id');
|
||||
|
||||
// ✅ INI KUNCINYA
|
||||
$this->db->having('stok >', 0);
|
||||
|
||||
|
||||
$data = $this->db->get()->result();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Jurnal extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
||||
// if($this->session->userdata('role') != 'Admin'){
|
||||
// show_error('Akses ditolak', 403);
|
||||
// }
|
||||
|
||||
$data = ["active_menu" => "jurnal"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('jurnal/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET DATA DATATABLE (SUDAH ADA TOTAL)
|
||||
// =========================
|
||||
public function get_data()
|
||||
{
|
||||
$draw = $_POST['draw'];
|
||||
$start = $_POST['start'];
|
||||
$length = $_POST['length'];
|
||||
$search = $_POST['search']['value'];
|
||||
|
||||
// ================= TOTAL ALL
|
||||
$totalAll = $this->db->count_all('journals');
|
||||
|
||||
// ================= QUERY FILTERED (HITUNG)
|
||||
$this->db->from('journals');
|
||||
|
||||
if(!empty($search)){
|
||||
$this->db->group_start();
|
||||
$this->db->like('no_ref', $search);
|
||||
$this->db->or_like('keterangan', $search);
|
||||
$this->db->or_like('tanggal', $search);
|
||||
$this->db->group_end();
|
||||
}
|
||||
|
||||
$filtered = $this->db->count_all_results();
|
||||
|
||||
// ================= QUERY DATA (AMBIL DATA)
|
||||
$this->db->select('
|
||||
journals.id,
|
||||
journals.tanggal,
|
||||
journals.no_ref,
|
||||
journals.keterangan,
|
||||
COALESCE(SUM(journal_details.debit),0) as total_debit,
|
||||
COALESCE(SUM(journal_details.kredit),0) as total_kredit
|
||||
');
|
||||
$this->db->from('journals');
|
||||
$this->db->join('journal_details','journal_details.journal_id = journals.id','LEFT');
|
||||
|
||||
if(!empty($search)){
|
||||
$this->db->group_start();
|
||||
$this->db->like('journals.no_ref', $search);
|
||||
$this->db->or_like('journals.keterangan', $search);
|
||||
$this->db->or_like('journals.tanggal', $search);
|
||||
$this->db->group_end();
|
||||
}
|
||||
|
||||
$this->db->group_by('journals.id');
|
||||
$this->db->order_by('journals.tanggal','DESC');
|
||||
$this->db->order_by('journals.created_at','DESC');
|
||||
$this->db->limit($length, $start);
|
||||
|
||||
$query = $this->db->get()->result();
|
||||
|
||||
// ================= FORMAT
|
||||
$data = [];
|
||||
$no = $start;
|
||||
|
||||
foreach ($query as $row) {
|
||||
$no++;
|
||||
|
||||
if($this->session->userdata('role') != 'Admin'){
|
||||
|
||||
$aksi = '
|
||||
<button class="btn btn-sm btn-info btn-detail" data-id="'.$row->id.'">Detail</button>
|
||||
';
|
||||
|
||||
}
|
||||
else {
|
||||
$aksi = '
|
||||
<button class="btn btn-sm btn-info btn-detail" data-id="'.$row->id.'">Detail</button>
|
||||
<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Delete</button>
|
||||
';
|
||||
}
|
||||
|
||||
$data[] = [
|
||||
$no,
|
||||
$row->tanggal,
|
||||
$row->no_ref,
|
||||
$row->keterangan,
|
||||
number_format($row->total_debit,0,',','.'),
|
||||
number_format($row->total_kredit,0,',','.'),
|
||||
$aksi
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"draw" => $draw,
|
||||
"recordsTotal" => $totalAll,
|
||||
"recordsFiltered" => $filtered,
|
||||
"data" => $data
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET ACCOUNTS
|
||||
// =========================
|
||||
public function get_accounts()
|
||||
{
|
||||
$data = $this->db->order_by('kode_akun','ASC')->get('accounts')->result();
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// SAVE
|
||||
// =========================
|
||||
public function save()
|
||||
{
|
||||
$tanggal = $this->input->post('tanggal');
|
||||
$no_ref = 'JR-' . date('YmdHis');
|
||||
$keterangan = $this->input->post('keterangan');
|
||||
|
||||
$accounts = $this->input->post('account_id');
|
||||
$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;
|
||||
}
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
$this->db->insert('journals', [
|
||||
'tanggal' => $tanggal,
|
||||
'no_ref' => $no_ref,
|
||||
'keterangan' => $keterangan,
|
||||
'created_by' => $this->session->userdata('user_id')
|
||||
]);
|
||||
|
||||
$journal_id = $this->db->insert_id();
|
||||
|
||||
for ($i=0; $i<count($accounts); $i++) {
|
||||
if ($accounts[$i] == '') continue;
|
||||
|
||||
$this->db->insert('journal_details', [
|
||||
'journal_id' => $journal_id,
|
||||
'account_id' => $accounts[$i],
|
||||
'debit' => $debit[$i] ?: 0,
|
||||
'kredit' => $kredit[$i] ?: 0
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
if ($this->db->trans_status() === FALSE) {
|
||||
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Gagal simpan jurnal'
|
||||
]);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// ================= LOG ACTIVITY =================
|
||||
log_activity(
|
||||
'Jurnal',
|
||||
'create',
|
||||
'Membuat jurnal No Ref: '.$no_ref,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status'=>true,
|
||||
'message'=>'Jurnal berhasil disimpan'
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DETAIL
|
||||
// =========================
|
||||
public function detail($id)
|
||||
{
|
||||
$header = $this->db->get_where('journals',['id'=>$id])->row();
|
||||
|
||||
$detail = $this->db
|
||||
->select('accounts.kode_akun, accounts.nama_akun, journal_details.*')
|
||||
->from('journal_details')
|
||||
->join('accounts','accounts.id = journal_details.account_id')
|
||||
->where('journal_id',$id)
|
||||
->get()->result();
|
||||
|
||||
// print_r($header);
|
||||
|
||||
$userid = $header->created_by;
|
||||
$user = $this->db
|
||||
->select('nama')
|
||||
->where('id', $userid)
|
||||
->get('users')
|
||||
->row();
|
||||
|
||||
echo json_encode([
|
||||
'header'=>$header,
|
||||
'detail'=>$detail,
|
||||
'user' =>$user
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DELETE
|
||||
// =========================
|
||||
public function delete($id)
|
||||
{
|
||||
$journal = $this->db->get_where('journals', ['id' => $id])->row();
|
||||
|
||||
// VALIDASI
|
||||
if (!$journal) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Jurnal tidak ditemukan'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->trans_start();
|
||||
|
||||
// =========================
|
||||
// HANDLE STOCK LOGS
|
||||
// =========================
|
||||
if ($journal->ref_type == 'stock_logs') {
|
||||
|
||||
$stock = $this->db
|
||||
->select('item_id, warehouse_id')
|
||||
->where('id', $journal->ref_id)
|
||||
->get('stock_logs')
|
||||
->row();
|
||||
|
||||
if ($stock) {
|
||||
|
||||
// hapus log stok
|
||||
$this->db->delete('stock_logs', ['id' => $journal->ref_id]);
|
||||
|
||||
// update stok ulang (pakai item_id saja biar gak ganggu sistem lama)
|
||||
$this->update_item_stok($stock->item_id);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DELETE JOURNAL
|
||||
// =========================
|
||||
$this->db->delete('journal_details', ['journal_id' => $id]);
|
||||
$this->db->delete('journals', ['id' => $id]);
|
||||
|
||||
$this->db->trans_complete();
|
||||
|
||||
// =========================
|
||||
// VALIDASI TRANSAKSI
|
||||
// =========================
|
||||
if (!$this->db->trans_status()) {
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Gagal hapus jurnal'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// ================= LOG ACTIVITY =================
|
||||
log_activity(
|
||||
'Jurnal',
|
||||
'delete',
|
||||
'Menghapus jurnal no_ref: ' . $journal->no_ref . ' ket: ' . $journal->keterangan,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true, // ✅ FIX
|
||||
'message' => 'Jurnal berhasil dihapus',
|
||||
'journal' => $journal->ref_type
|
||||
]);
|
||||
}
|
||||
|
||||
public function get_base_jurnal()
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->order_by('kode','ASC')->get('base_journal')->result()
|
||||
);
|
||||
}
|
||||
|
||||
public function get_base_jurnal_detail($id)
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->where('base_journal_id',$id)
|
||||
->get('base_journal_detail')
|
||||
->result()
|
||||
);
|
||||
}
|
||||
|
||||
private function update_item_stok($item_id)
|
||||
{
|
||||
$stok = $this->db->query("
|
||||
SELECT COALESCE(SUM(qty * IF(tipe='masuk',1,-1)),0) as stok
|
||||
FROM stock_logs
|
||||
WHERE item_id = ?
|
||||
", [$item_id])->row()->stok;
|
||||
|
||||
$this->db->where('id', $item_id)
|
||||
->update('items', [
|
||||
'stok' => $stok
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Kodebarang extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data = ["active_menu" => "kode_barang"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('kode_barang/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET DATA (DATATABLE)
|
||||
// =========================
|
||||
public function get_data()
|
||||
{
|
||||
$data = $this->db->get('kode_barang')->result();
|
||||
|
||||
$result = [];
|
||||
$no = 1;
|
||||
|
||||
foreach ($data as $row) {
|
||||
$result[] = [
|
||||
$no++,
|
||||
$row->kode_barang,
|
||||
$row->nama,
|
||||
$row->limit_stock,
|
||||
'
|
||||
<button class="btn btn-sm btn-secondary btn-editkode" data-id="'.$row->id.'">Edit</button>
|
||||
<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Delete</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode(["data"=>$result]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DETAIL
|
||||
// =========================
|
||||
public function detail($id)
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->get_where('kode_barang',['id'=>$id])->row()
|
||||
);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// SAVE
|
||||
// =========================
|
||||
public function save()
|
||||
{
|
||||
$nama = $this->input->post('nama');
|
||||
$kode = $this->input->post('kode');
|
||||
$limit_stock = $this->input->post('limit_stock');
|
||||
|
||||
if(!$nama){
|
||||
echo json_encode(['status'=>false,'message'=>'Nama wajib diisi']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->insert('kode_barang', [
|
||||
'kode_barang' => $kode,
|
||||
'nama' => $nama,
|
||||
'limit_stock' => $limit_stock
|
||||
]);
|
||||
|
||||
log_activity(
|
||||
'kode_barang',
|
||||
'create',
|
||||
'Menambahkan kode barang: ' . $nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Gudang berhasil ditambahkan']);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// UPDATE
|
||||
// =========================
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
$kode = $this->input->post('kode');
|
||||
$nama = $this->input->post('nama');
|
||||
$limit_stock = $this->input->post('limit_stock');
|
||||
|
||||
if(!$nama){
|
||||
echo json_encode(['status'=>false,'message'=>'Nama wajib diisi']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->where('id',$id)->update('kode_barang', [
|
||||
'kode_barang' => $kode,
|
||||
'nama' => $nama,
|
||||
'limit_stock' => $limit_stock
|
||||
]);
|
||||
|
||||
log_activity(
|
||||
'kode_barang',
|
||||
'update',
|
||||
'Update kode barang ID: ' . $id . ' nama: ' . $nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Gudang berhasil diupdate']);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DELETE
|
||||
// =========================
|
||||
public function delete($id)
|
||||
{
|
||||
// optional: cek relasi ke items
|
||||
$cek = $this->db->get_where('items',['warehouse_id'=>$id])->num_rows();
|
||||
|
||||
if($cek > 0){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Gudang tidak bisa dihapus karena masih dipakai item'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->delete('kode_barang',['id'=>$id]);
|
||||
|
||||
log_activity(
|
||||
'kode_barang',
|
||||
'delete',
|
||||
'Hapus gudang ID: ' . $id,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Gudang berhasil dihapus']);
|
||||
}
|
||||
|
||||
|
||||
public function list()
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->get('kode_barang')->result()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Labarugi extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
if($this->session->userdata('role') != 'Admin'){
|
||||
show_error('Akses ditolak', 403);
|
||||
}
|
||||
|
||||
$data = ["active_menu" => "laba_rugi"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('laporan/laba_rugi');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
public function get_data()
|
||||
{
|
||||
$tanggal_dari = $this->input->get('tanggal_dari');
|
||||
$tanggal_sampai = $this->input->get('tanggal_sampai');
|
||||
|
||||
$this->db->select('
|
||||
a.id,
|
||||
a.kode_akun,
|
||||
a.nama_akun,
|
||||
a.tipe,
|
||||
COALESCE(SUM(jd.debit),0) as debit,
|
||||
COALESCE(SUM(jd.kredit),0) as kredit
|
||||
');
|
||||
$this->db->from('accounts a');
|
||||
|
||||
// ================= JOIN
|
||||
$this->db->join('journal_details jd','a.id = jd.account_id','LEFT');
|
||||
$this->db->join('journals j','j.id = jd.journal_id','LEFT');
|
||||
|
||||
// ================= FILTER AKUN
|
||||
$this->db->where('a.kategori','laba_rugi');
|
||||
$this->db->where('a.is_active',1);
|
||||
|
||||
// ================= FILTER TANGGAL (AMAN)
|
||||
if($tanggal_dari){
|
||||
$this->db->where('(j.tanggal >= "'.$tanggal_dari.'" OR j.tanggal IS NULL)');
|
||||
}
|
||||
|
||||
if($tanggal_sampai){
|
||||
$this->db->where('(j.tanggal <= "'.$tanggal_sampai.'" OR j.tanggal IS NULL)');
|
||||
}
|
||||
|
||||
$this->db->group_by('a.id');
|
||||
$this->db->order_by('a.kode_akun','ASC');
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
$revenue = 0;
|
||||
$expense = 0;
|
||||
|
||||
foreach ($rows as $r) {
|
||||
|
||||
if ($r->tipe == 'revenue') {
|
||||
$saldo = $r->kredit - $r->debit;
|
||||
$revenue += $saldo;
|
||||
}
|
||||
|
||||
if ($r->tipe == 'expense') {
|
||||
$saldo = $r->debit - $r->kredit;
|
||||
$expense += $saldo;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'data' => $rows,
|
||||
'revenue' => $revenue,
|
||||
'expense' => $expense,
|
||||
'laba' => $revenue - $expense
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Leaverequests extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->database();
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// PAGE
|
||||
// ==========================================
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
"active_menu" => "leave_requests"
|
||||
];
|
||||
|
||||
$data['employees'] = $this->db
|
||||
->where('is_active',1)
|
||||
->order_by('full_name','ASC')
|
||||
->get('k_employees')
|
||||
->result();
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('employees/leave_requests', $data);
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// DATATABLE
|
||||
// ==========================================
|
||||
public function get_data()
|
||||
{
|
||||
$this->db->select('
|
||||
lr.*,
|
||||
e.full_name,
|
||||
e.fingerprint_user_id
|
||||
');
|
||||
|
||||
$this->db->from('k_leave_requests lr');
|
||||
|
||||
$this->db->join(
|
||||
'k_employees e',
|
||||
'e.id=lr.employee_id',
|
||||
'left'
|
||||
);
|
||||
|
||||
$this->db->order_by('lr.id','DESC');
|
||||
|
||||
$list = $this->db->get()->result();
|
||||
|
||||
$data = [];
|
||||
$no = 1;
|
||||
|
||||
foreach($list as $r){
|
||||
|
||||
// =====================================
|
||||
// LEAVE TYPE
|
||||
// =====================================
|
||||
$leave_type = '-';
|
||||
|
||||
if($r->leave_type == 'annual'){
|
||||
$leave_type = 'Cuti Tahunan';
|
||||
}
|
||||
|
||||
if($r->leave_type == 'sick'){
|
||||
$leave_type = 'Sakit';
|
||||
}
|
||||
|
||||
if($r->leave_type == 'permit'){
|
||||
$leave_type = 'Izin';
|
||||
}
|
||||
|
||||
if($r->leave_type == 'maternity'){
|
||||
$leave_type = 'Cuti Melahirkan';
|
||||
}
|
||||
|
||||
if($r->leave_type == 'unpaid'){
|
||||
$leave_type = 'Cuti Tidak Dibayar';
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// STATUS
|
||||
// =====================================
|
||||
if($r->approval_status == 'approved'){
|
||||
|
||||
$status = '
|
||||
<span class="badge bg-success">
|
||||
Disetujui
|
||||
</span>
|
||||
';
|
||||
|
||||
} elseif($r->approval_status == 'rejected'){
|
||||
|
||||
$status = '
|
||||
<span class="badge bg-danger">
|
||||
Ditolak
|
||||
</span>
|
||||
';
|
||||
|
||||
} else {
|
||||
|
||||
$status = '
|
||||
<span class="badge bg-warning text-dark">
|
||||
Pending
|
||||
</span>
|
||||
';
|
||||
}
|
||||
|
||||
$data[] = [
|
||||
$no++,
|
||||
$r->fingerprint_user_id,
|
||||
$r->full_name,
|
||||
$leave_type,
|
||||
$r->start_date,
|
||||
$r->end_date,
|
||||
$r->total_days . ' Hari',
|
||||
$status,
|
||||
'
|
||||
<button class="btn btn-warning btn-sm btn-edit"
|
||||
data-id="'.$r->id.'">
|
||||
|
||||
Edit
|
||||
|
||||
</button>
|
||||
|
||||
<button class="btn btn-danger btn-sm btn-delete"
|
||||
data-id="'.$r->id.'">
|
||||
|
||||
Delete
|
||||
|
||||
</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"data" => $data
|
||||
]);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// DETAIL
|
||||
// ==========================================
|
||||
public function detail($id)
|
||||
{
|
||||
$data = $this->db
|
||||
->get_where(
|
||||
'k_leave_requests',
|
||||
['id'=>$id]
|
||||
)
|
||||
->row();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// SAVE
|
||||
// ==========================================
|
||||
public function save()
|
||||
{
|
||||
try{
|
||||
|
||||
$start_date = $this->input->post('start_date');
|
||||
$end_date = $this->input->post('end_date');
|
||||
|
||||
$total_days = (
|
||||
strtotime($end_date)
|
||||
-
|
||||
strtotime($start_date)
|
||||
) / 86400 + 1;
|
||||
|
||||
$data = [
|
||||
|
||||
'employee_id' => $this->input->post('employee_id'),
|
||||
|
||||
'leave_type' => $this->input->post('leave_type'),
|
||||
|
||||
'start_date' => $start_date,
|
||||
|
||||
'end_date' => $end_date,
|
||||
|
||||
'total_days' => $total_days,
|
||||
|
||||
'reason' => $this->input->post('reason'),
|
||||
|
||||
'approval_status' => $this->input->post('approval_status')
|
||||
];
|
||||
|
||||
$this->db->insert(
|
||||
'k_leave_requests',
|
||||
$data
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message'=> 'Leave request berhasil ditambahkan'
|
||||
]);
|
||||
|
||||
} catch(Exception $e){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message'=> $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// UPDATE
|
||||
// ==========================================
|
||||
public function update()
|
||||
{
|
||||
try{
|
||||
|
||||
$id = $this->input->post('id');
|
||||
|
||||
$start_date = $this->input->post('start_date');
|
||||
$end_date = $this->input->post('end_date');
|
||||
|
||||
$total_days = (
|
||||
strtotime($end_date)
|
||||
-
|
||||
strtotime($start_date)
|
||||
) / 86400 + 1;
|
||||
|
||||
$data = [
|
||||
|
||||
'employee_id' => $this->input->post('employee_id'),
|
||||
|
||||
'leave_type' => $this->input->post('leave_type'),
|
||||
|
||||
'start_date' => $start_date,
|
||||
|
||||
'end_date' => $end_date,
|
||||
|
||||
'total_days' => $total_days,
|
||||
|
||||
'reason' => $this->input->post('reason'),
|
||||
|
||||
'approval_status' => $this->input->post('approval_status')
|
||||
];
|
||||
|
||||
$this->db->where('id',$id);
|
||||
|
||||
$this->db->update(
|
||||
'k_leave_requests',
|
||||
$data
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message'=> 'Leave request berhasil diupdate'
|
||||
]);
|
||||
|
||||
} catch(Exception $e){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message'=> $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// DELETE
|
||||
// ==========================================
|
||||
public function delete($id)
|
||||
{
|
||||
$this->db->delete(
|
||||
'k_leave_requests',
|
||||
['id'=>$id]
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message'=> 'Leave request berhasil dihapus'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Lokasiasset extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data = ["active_menu" => "lokasiasset"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('lokasi_asset/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET DATA (DATATABLE)
|
||||
// =========================
|
||||
public function get_data()
|
||||
{
|
||||
$data = $this->db->get('lokasi_asset')->result();
|
||||
|
||||
$result = [];
|
||||
$no = 1;
|
||||
|
||||
foreach ($data as $row) {
|
||||
$result[] = [
|
||||
$no++,
|
||||
$row->nama,
|
||||
'
|
||||
<button class="btn btn-sm btn-secondary btn-editgudang" data-id="'.$row->id.'">Edit</button>
|
||||
<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Delete</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode(["data"=>$result]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DETAIL
|
||||
// =========================
|
||||
public function detail($id)
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->get_where('lokasi_asset',['id'=>$id])->row()
|
||||
);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// SAVE
|
||||
// =========================
|
||||
public function save()
|
||||
{
|
||||
$nama = $this->input->post('nama');
|
||||
|
||||
if(!$nama){
|
||||
echo json_encode(['status'=>false,'message'=>'Nama wajib diisi']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->insert('lokasi_asset', [
|
||||
'nama' => $nama
|
||||
]);
|
||||
|
||||
log_activity(
|
||||
'kode_barang',
|
||||
'create',
|
||||
'Tambah gudang '.$nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Gudang berhasil ditambahkan']);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// UPDATE
|
||||
// =========================
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
$nama = $this->input->post('nama');
|
||||
|
||||
if(!$nama){
|
||||
echo json_encode(['status'=>false,'message'=>'Nama wajib diisi']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->where('id',$id)->update('lokasi_asset', [
|
||||
'nama' => $nama
|
||||
]);
|
||||
|
||||
log_activity(
|
||||
'kode_barang',
|
||||
'update',
|
||||
'Update gudang '.$nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Gudang berhasil diupdate']);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DELETE
|
||||
// =========================
|
||||
public function delete($id)
|
||||
{
|
||||
// optional: cek relasi ke items
|
||||
$cek = $this->db->get_where('assets',['lokasi_asset_id'=>$id])->num_rows();
|
||||
|
||||
if($cek > 0){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Gudang tidak bisa dihapus karena masih dipakai item'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->delete('lokasi_asset',['id'=>$id]);
|
||||
|
||||
log_activity(
|
||||
'kode_barang',
|
||||
'delete',
|
||||
'Delete gudang '.$nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Gudang berhasil dihapus']);
|
||||
}
|
||||
|
||||
|
||||
public function list()
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->get('lokasi_asset')->result()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Neraca extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
if($this->session->userdata('role') != 'Admin'){
|
||||
show_error('Akses ditolak', 403);
|
||||
}
|
||||
|
||||
$data = ["active_menu" => "neraca"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('laporan/neraca');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// LABA BERJALAN (PAKAI TANGGAL JOURNAL)
|
||||
// =========================
|
||||
private function get_laba_berjalan($tanggal_dari = null, $tanggal_sampai = null)
|
||||
{
|
||||
$this->db->select('
|
||||
accounts.tipe,
|
||||
COALESCE(SUM(jd.debit),0) as debit,
|
||||
COALESCE(SUM(jd.kredit),0) as kredit
|
||||
');
|
||||
$this->db->from('accounts');
|
||||
$this->db->join('journal_details jd','jd.account_id = accounts.id','LEFT');
|
||||
$this->db->join('journals j','j.id = jd.journal_id','LEFT');
|
||||
|
||||
$this->db->where_in('accounts.tipe',['revenue','expense']);
|
||||
|
||||
// ================= FILTER TANGGAL
|
||||
if($tanggal_dari){
|
||||
$this->db->where('(j.tanggal >= "'.$tanggal_dari.'" OR j.tanggal IS NULL)');
|
||||
}
|
||||
|
||||
if($tanggal_sampai){
|
||||
$this->db->where('(j.tanggal <= "'.$tanggal_sampai.'" OR j.tanggal IS NULL)');
|
||||
}
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
$revenue = 0;
|
||||
$expense = 0;
|
||||
|
||||
foreach ($rows as $r) {
|
||||
if ($r->tipe == 'revenue') {
|
||||
$revenue += ($r->kredit - $r->debit);
|
||||
} else {
|
||||
$expense += ($r->debit - $r->kredit);
|
||||
}
|
||||
}
|
||||
|
||||
return $revenue - $expense;
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET DATA NERACA
|
||||
// =========================
|
||||
public function get_data()
|
||||
{
|
||||
$tanggal_dari = $this->input->get('tanggal_dari');
|
||||
$tanggal_sampai = $this->input->get('tanggal_sampai');
|
||||
|
||||
$this->db->select('
|
||||
a.id,
|
||||
a.kode_akun,
|
||||
a.nama_akun,
|
||||
a.tipe,
|
||||
a.posisi,
|
||||
a.is_kontra,
|
||||
COALESCE(SUM(jd.debit),0) as debit,
|
||||
COALESCE(SUM(jd.kredit),0) as kredit
|
||||
');
|
||||
$this->db->from('accounts a');
|
||||
$this->db->join('journal_details jd','jd.account_id = a.id','LEFT');
|
||||
$this->db->join('journals j','j.id = jd.journal_id','LEFT');
|
||||
|
||||
$this->db->where('a.kategori','neraca');
|
||||
|
||||
// ================= FILTER TANGGAL
|
||||
if($tanggal_dari){
|
||||
$this->db->where('(j.tanggal >= "'.$tanggal_dari.'" OR j.tanggal IS NULL)');
|
||||
}
|
||||
|
||||
if($tanggal_sampai){
|
||||
$this->db->where('(j.tanggal <= "'.$tanggal_sampai.'" OR j.tanggal IS NULL)');
|
||||
}
|
||||
|
||||
$this->db->group_by('a.id');
|
||||
$this->db->order_by('a.kode_akun','ASC');
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
$activa = [];
|
||||
$pasiva = [];
|
||||
|
||||
$total_activa = 0;
|
||||
$total_pasiva = 0;
|
||||
|
||||
// ================= LABA BERJALAN
|
||||
$laba = $this->get_laba_berjalan($tanggal_dari, $tanggal_sampai);
|
||||
|
||||
foreach ($rows as $r) {
|
||||
|
||||
// ================= SALDO NORMAL
|
||||
if ($r->posisi == 'debit') {
|
||||
$saldo = $r->debit - $r->kredit;
|
||||
} else {
|
||||
$saldo = $r->kredit - $r->debit;
|
||||
}
|
||||
|
||||
// ================= KONTRA ACCOUNT
|
||||
if ($r->is_kontra == 1) {
|
||||
$saldo = -$saldo;
|
||||
}
|
||||
|
||||
// ================= LABA BERJALAN
|
||||
if ($r->kode_akun == '302') {
|
||||
$saldo = $laba;
|
||||
}
|
||||
|
||||
// ================= ACTIVA
|
||||
if ($r->tipe == 'asset') {
|
||||
|
||||
$activa[] = [
|
||||
'kode' => $r->kode_akun,
|
||||
'nama' => $r->nama_akun,
|
||||
'saldo' => $saldo
|
||||
];
|
||||
|
||||
$total_activa += $saldo;
|
||||
}
|
||||
|
||||
// ================= PASIVA
|
||||
if (in_array($r->tipe, ['liability','equity'])) {
|
||||
|
||||
$pasiva[] = [
|
||||
'kode' => $r->kode_akun,
|
||||
'nama' => $r->nama_akun,
|
||||
'saldo' => $saldo
|
||||
];
|
||||
|
||||
$total_pasiva += $saldo;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'activa' => $activa,
|
||||
'pasiva' => $pasiva,
|
||||
'total_activa' => $total_activa,
|
||||
'total_pasiva' => $total_pasiva,
|
||||
'laba' => $laba,
|
||||
'selisih' => $total_activa - $total_pasiva
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Neracasaldo extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
||||
if($this->session->userdata('role') != 'Admin'){
|
||||
show_error('Akses ditolak', 403);
|
||||
}
|
||||
|
||||
$data = ["active_menu" => "neraca_saldo"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('laporan/neraca_saldo');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// HITUNG LABA BERJALAN (REALTIME)
|
||||
// =========================
|
||||
private function get_laba_berjalan()
|
||||
{
|
||||
$this->db->select('
|
||||
accounts.tipe,
|
||||
COALESCE(SUM(journal_details.debit),0) as debit,
|
||||
COALESCE(SUM(journal_details.kredit),0) as kredit
|
||||
');
|
||||
$this->db->from('accounts');
|
||||
$this->db->join('journal_details','journal_details.account_id = accounts.id','LEFT');
|
||||
$this->db->where_in('accounts.tipe',['revenue','expense']);
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
$revenue = 0;
|
||||
$expense = 0;
|
||||
|
||||
foreach ($rows as $r) {
|
||||
if ($r->tipe == 'revenue') {
|
||||
$revenue += ($r->kredit - $r->debit);
|
||||
} else {
|
||||
$expense += ($r->debit - $r->kredit);
|
||||
}
|
||||
}
|
||||
|
||||
return $revenue - $expense;
|
||||
}
|
||||
|
||||
public function get_data()
|
||||
{
|
||||
$this->db->select('
|
||||
accounts.kode_akun,
|
||||
accounts.nama_akun,
|
||||
accounts.tipe,
|
||||
accounts.posisi,
|
||||
COALESCE(SUM(journal_details.debit),0) as debit,
|
||||
COALESCE(SUM(journal_details.kredit),0) as kredit
|
||||
');
|
||||
$this->db->from('accounts');
|
||||
$this->db->join('journal_details','journal_details.account_id = accounts.id','LEFT');
|
||||
|
||||
// OPTIONAL (best practice)
|
||||
$this->db->where('accounts.is_active',1);
|
||||
$this->db->where('accounts.kategori','neraca');
|
||||
|
||||
$this->db->group_by('accounts.id');
|
||||
$this->db->order_by('accounts.kode_akun','ASC');
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
// =========================
|
||||
// HITUNG LABA BERJALAN
|
||||
// =========================
|
||||
$laba = $this->get_laba_berjalan();
|
||||
|
||||
foreach ($rows as $r) {
|
||||
|
||||
// ================= SALDO NORMAL
|
||||
if ($r->posisi == 'debit') {
|
||||
$saldo = $r->debit - $r->kredit;
|
||||
} else {
|
||||
$saldo = $r->kredit - $r->debit;
|
||||
}
|
||||
|
||||
// ================= OVERRIDE LABA BERJALAN
|
||||
if ($r->kode_akun == '302') {
|
||||
$saldo = $laba;
|
||||
}
|
||||
|
||||
// ================= NORMALISASI KE KOLOM
|
||||
if ($saldo >= 0 AND $r->posisi == 'debit') {
|
||||
$r->saldo_debit = $saldo;
|
||||
$r->saldo_kredit = 0;
|
||||
} else {
|
||||
$r->saldo_debit = 0;
|
||||
$r->saldo_kredit = abs($saldo);
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($rows);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,598 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Payroll extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->database();
|
||||
|
||||
date_default_timezone_set('Asia/Jakarta');
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// INDEX
|
||||
// =====================================================
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
'active_menu' => 'payroll'
|
||||
];
|
||||
|
||||
$this->load->view('partials/header',$data);
|
||||
$this->load->view('employees/payroll');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// GET DATA
|
||||
// =====================================================
|
||||
public function get_data()
|
||||
{
|
||||
$month = $this->input->post('month');
|
||||
|
||||
$this->db->select("
|
||||
p.*,
|
||||
e.full_name,
|
||||
pp.period_name,
|
||||
pp.start_date,
|
||||
pp.end_date
|
||||
");
|
||||
|
||||
$this->db->from('k_payrolls p');
|
||||
|
||||
$this->db->join(
|
||||
'k_employees e',
|
||||
'e.id = p.employee_id'
|
||||
);
|
||||
|
||||
$this->db->join(
|
||||
'k_payroll_periods pp',
|
||||
'pp.id = p.payroll_period_id'
|
||||
);
|
||||
|
||||
if($month){
|
||||
|
||||
$this->db->where(
|
||||
'DATE_FORMAT(pp.start_date,"%Y-%m")',
|
||||
$month
|
||||
);
|
||||
}
|
||||
|
||||
$this->db->order_by(
|
||||
'e.full_name',
|
||||
'ASC'
|
||||
);
|
||||
|
||||
$rows = $this->db->get()->result();
|
||||
|
||||
$data = [];
|
||||
|
||||
$no = 1;
|
||||
|
||||
foreach($rows as $row){
|
||||
|
||||
$pendapatan =
|
||||
(
|
||||
$row->allowance_amount
|
||||
+
|
||||
$row->bonus_amount
|
||||
+
|
||||
$row->overtime_amount
|
||||
);
|
||||
|
||||
$potongan =
|
||||
(
|
||||
$row->deduction_amount
|
||||
+
|
||||
$row->bpjs_kesehatan_amount
|
||||
+
|
||||
$row->bpjs_ketenagakerjaan_amount
|
||||
+
|
||||
$row->tax_amount
|
||||
+
|
||||
$row->attendance_cut_amount
|
||||
);
|
||||
|
||||
$status = '';
|
||||
|
||||
if($row->payment_status == 'paid'){
|
||||
|
||||
$status = '
|
||||
<span class="badge bg-success">
|
||||
Paid
|
||||
</span>
|
||||
';
|
||||
|
||||
} else {
|
||||
|
||||
$status = '
|
||||
<span class="badge bg-warning text-dark">
|
||||
Draft
|
||||
</span>
|
||||
';
|
||||
}
|
||||
|
||||
$data[] = [
|
||||
|
||||
$no++,
|
||||
|
||||
$row->full_name,
|
||||
|
||||
'Rp '.number_format(
|
||||
$row->basic_salary,
|
||||
0,
|
||||
',',
|
||||
'.'
|
||||
),
|
||||
|
||||
'Rp '.number_format(
|
||||
$pendapatan,
|
||||
0,
|
||||
',',
|
||||
'.'
|
||||
),
|
||||
|
||||
'Rp '.number_format(
|
||||
$potongan,
|
||||
0,
|
||||
',',
|
||||
'.'
|
||||
),
|
||||
|
||||
'Rp '.number_format(
|
||||
$row->total_salary,
|
||||
0,
|
||||
',',
|
||||
'.'
|
||||
),
|
||||
|
||||
$status,
|
||||
|
||||
'
|
||||
<button
|
||||
class="btn btn-sm btn-warning btn-edit"
|
||||
data-id="'.$row->id.'">
|
||||
|
||||
<i class="fa fa-edit"></i>
|
||||
Edit
|
||||
|
||||
</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'data' => $data
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// DETAIL
|
||||
// =====================================================
|
||||
public function detail($id)
|
||||
{
|
||||
$this->db->select("
|
||||
p.*,
|
||||
e.full_name
|
||||
");
|
||||
|
||||
$this->db->from('k_payrolls p');
|
||||
|
||||
$this->db->join(
|
||||
'k_employees e',
|
||||
'e.id = p.employee_id'
|
||||
);
|
||||
|
||||
$this->db->where(
|
||||
'p.id',
|
||||
$id
|
||||
);
|
||||
|
||||
$payroll = $this->db->get()->row();
|
||||
|
||||
if(!$payroll){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Payroll tidak ditemukan'
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$items = $this->db
|
||||
->where('payroll_id',$id)
|
||||
->order_by('id','ASC')
|
||||
->get('k_payroll_items')
|
||||
->result();
|
||||
|
||||
echo json_encode([
|
||||
|
||||
'status' => true,
|
||||
|
||||
'payroll' => $payroll,
|
||||
|
||||
'employee' => [
|
||||
'full_name' => $payroll->full_name
|
||||
],
|
||||
|
||||
'items' => $items
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// SAVE ITEMS
|
||||
// =====================================================
|
||||
public function save_items()
|
||||
{
|
||||
$payrollId = $this->input->post('payroll_id');
|
||||
|
||||
$items = $this->input->post('items');
|
||||
|
||||
$payroll = $this->db
|
||||
->where('id',$payrollId)
|
||||
->get('k_payrolls')
|
||||
->row();
|
||||
|
||||
if(!$payroll){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Payroll tidak ditemukan'
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// DELETE OLD ITEMS
|
||||
// =========================================
|
||||
$this->db
|
||||
->where('payroll_id',$payrollId)
|
||||
->delete('k_payroll_items');
|
||||
|
||||
$allowance = 0;
|
||||
$bonus = 0;
|
||||
$overtime = 0;
|
||||
$deduction = 0;
|
||||
$bpjs = 0;
|
||||
$tax = 0;
|
||||
|
||||
if($items){
|
||||
|
||||
foreach($items as $item){
|
||||
|
||||
$amount = (float)$item['amount'];
|
||||
|
||||
$insert = [
|
||||
|
||||
'payroll_id' => $payrollId,
|
||||
|
||||
'item_type' => $item['item_type'],
|
||||
|
||||
'item_name' => $item['item_name'],
|
||||
|
||||
'amount' => $amount
|
||||
];
|
||||
|
||||
$this->db->insert(
|
||||
'k_payroll_items',
|
||||
$insert
|
||||
);
|
||||
|
||||
switch($item['item_type']){
|
||||
|
||||
case 'allowance':
|
||||
$allowance += $amount;
|
||||
break;
|
||||
|
||||
case 'bonus':
|
||||
$bonus += $amount;
|
||||
break;
|
||||
|
||||
case 'overtime':
|
||||
$overtime += $amount;
|
||||
break;
|
||||
|
||||
case 'deduction':
|
||||
$deduction += $amount;
|
||||
break;
|
||||
|
||||
case 'bpjs':
|
||||
$bpjs += $amount;
|
||||
break;
|
||||
|
||||
case 'tax':
|
||||
$tax += $amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// TOTAL
|
||||
// =========================================
|
||||
$totalSalary =
|
||||
(
|
||||
$payroll->basic_salary
|
||||
+
|
||||
$allowance
|
||||
+
|
||||
$bonus
|
||||
+
|
||||
$overtime
|
||||
)
|
||||
-
|
||||
(
|
||||
$deduction
|
||||
+
|
||||
$bpjs
|
||||
+
|
||||
$tax
|
||||
+
|
||||
$payroll->attendance_cut_amount
|
||||
);
|
||||
|
||||
// =========================================
|
||||
// UPDATE PAYROLL
|
||||
// =========================================
|
||||
$this->db
|
||||
->where('id',$payrollId)
|
||||
->update(
|
||||
'k_payrolls',
|
||||
[
|
||||
|
||||
'allowance_amount' => $allowance,
|
||||
|
||||
'bonus_amount' => $bonus,
|
||||
|
||||
'overtime_amount' => $overtime,
|
||||
|
||||
'deduction_amount' => $deduction,
|
||||
|
||||
'bpjs_kesehatan_amount' => $bpjs,
|
||||
|
||||
'tax_amount' => $tax,
|
||||
|
||||
'total_salary' => $totalSalary
|
||||
]
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Payroll berhasil disimpan'
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// GENERATE PAYROLL
|
||||
// =====================================================
|
||||
public function generate_payroll()
|
||||
{
|
||||
$month = $this->input->post('month');
|
||||
|
||||
if(!$month){
|
||||
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'Bulan wajib dipilih'
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$startDate = date(
|
||||
'Y-m-01',
|
||||
strtotime($month)
|
||||
);
|
||||
|
||||
$endDate = date(
|
||||
'Y-m-t',
|
||||
strtotime($month)
|
||||
);
|
||||
|
||||
// =========================================
|
||||
// PERIOD
|
||||
// =========================================
|
||||
$period = $this->db
|
||||
->where('start_date',$startDate)
|
||||
->where('end_date',$endDate)
|
||||
->get('k_payroll_periods')
|
||||
->row();
|
||||
|
||||
if(!$period){
|
||||
|
||||
$this->db->insert(
|
||||
'k_payroll_periods',
|
||||
[
|
||||
|
||||
'period_name' => date(
|
||||
'F Y',
|
||||
strtotime($startDate)
|
||||
),
|
||||
|
||||
'start_date' => $startDate,
|
||||
|
||||
'end_date' => $endDate,
|
||||
|
||||
'status' => 'draft',
|
||||
|
||||
'generated_at' => date('Y-m-d H:i:s')
|
||||
]
|
||||
);
|
||||
|
||||
$periodId = $this->db->insert_id();
|
||||
|
||||
} else {
|
||||
|
||||
$periodId = $period->id;
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// EMPLOYEES
|
||||
// =========================================
|
||||
$employees = $this->db
|
||||
->where('is_active',1)
|
||||
->get('k_employees')
|
||||
->result();
|
||||
|
||||
foreach($employees as $employee){
|
||||
|
||||
// =====================================
|
||||
// ATTENDANCE
|
||||
// =====================================
|
||||
$attendance = $this->db
|
||||
->select("
|
||||
COUNT(*) as total_work_days,
|
||||
|
||||
SUM(attendance_status='present')
|
||||
as total_present,
|
||||
|
||||
SUM(attendance_status='alpha')
|
||||
as total_alpha,
|
||||
|
||||
SUM(overtime_hours)
|
||||
as total_overtime_hours
|
||||
")
|
||||
->where('employee_id',$employee->id)
|
||||
->where('attendance_date >=',$startDate)
|
||||
->where('attendance_date <=',$endDate)
|
||||
->get('k_attendances')
|
||||
->row();
|
||||
|
||||
$dailySalary =
|
||||
$employee->basic_salary / 30;
|
||||
|
||||
$alphaCut =
|
||||
(
|
||||
$attendance->total_alpha
|
||||
* $dailySalary
|
||||
);
|
||||
|
||||
$overtimeRate = 25000;
|
||||
|
||||
$overtimeAmount =
|
||||
(
|
||||
$attendance->total_overtime_hours
|
||||
* $overtimeRate
|
||||
);
|
||||
|
||||
$totalSalary =
|
||||
(
|
||||
$employee->basic_salary
|
||||
+ $overtimeAmount
|
||||
)
|
||||
- $alphaCut;
|
||||
|
||||
$exist = $this->db
|
||||
->where(
|
||||
'payroll_period_id',
|
||||
$periodId
|
||||
)
|
||||
->where(
|
||||
'employee_id',
|
||||
$employee->id
|
||||
)
|
||||
->get('k_payrolls')
|
||||
->row();
|
||||
|
||||
$data = [
|
||||
|
||||
'payroll_period_id' => $periodId,
|
||||
|
||||
'employee_id' => $employee->id,
|
||||
|
||||
'basic_salary' => $employee->basic_salary,
|
||||
|
||||
'total_work_days' => (
|
||||
$attendance->total_work_days ?? 0
|
||||
),
|
||||
|
||||
'total_present' => (
|
||||
$attendance->total_present ?? 0
|
||||
),
|
||||
|
||||
'total_alpha' => (
|
||||
$attendance->total_alpha ?? 0
|
||||
),
|
||||
|
||||
'total_overtime_hours' => (
|
||||
$attendance->total_overtime_hours ?? 0
|
||||
),
|
||||
|
||||
'attendance_cut_amount' => $alphaCut,
|
||||
|
||||
'overtime_amount' => $overtimeAmount,
|
||||
|
||||
'total_salary' => $totalSalary
|
||||
];
|
||||
|
||||
if($exist){
|
||||
|
||||
$this->db
|
||||
->where('id',$exist->id)
|
||||
->update(
|
||||
'k_payrolls',
|
||||
$data
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
$this->db->insert(
|
||||
'k_payrolls',
|
||||
$data
|
||||
);
|
||||
|
||||
$payrollId = $this->db->insert_id();
|
||||
|
||||
// =================================
|
||||
// AUTO ITEM OVERTIME
|
||||
// =================================
|
||||
if($overtimeAmount > 0){
|
||||
|
||||
$this->db->insert(
|
||||
'k_payroll_items',
|
||||
[
|
||||
|
||||
'payroll_id' => $payrollId,
|
||||
|
||||
'item_type' => 'overtime',
|
||||
|
||||
'item_name' => 'Lembur',
|
||||
|
||||
'amount' => $overtimeAmount
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// =================================
|
||||
// AUTO ITEM ALPHA
|
||||
// =================================
|
||||
if($alphaCut > 0){
|
||||
|
||||
$this->db->insert(
|
||||
'k_payroll_items',
|
||||
[
|
||||
|
||||
'payroll_id' => $payrollId,
|
||||
|
||||
'item_type' => 'deduction',
|
||||
|
||||
'item_name' => 'Potongan Alpha',
|
||||
|
||||
'amount' => $alphaCut
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'Payroll berhasil digenerate'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Pesan extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->database();
|
||||
|
||||
// Cek apakah user sudah login
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('login');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
if (!check_permission('pesan', 'can_view')) {
|
||||
show_error('Tidak memiliki izin untuk melihat detail.', 403);
|
||||
}
|
||||
|
||||
$data = [
|
||||
"active_menu" => "pesan"
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('pesan/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// DATATABLE SERVERSIDE
|
||||
// =========================================================
|
||||
public function get_data()
|
||||
{
|
||||
|
||||
if (!check_permission('pesan', 'can_view')) {
|
||||
show_error('Tidak memiliki izin untuk melihat detail.', 403);
|
||||
}
|
||||
|
||||
$table = 'notifikasi';
|
||||
$column_order = array(null, 'created_at', 'type', 'nomor_whatsapp', 'email', 'pesan', 'status');
|
||||
$column_search = array('pesan', 'nomor_whatsapp', 'email', 'status', 'type');
|
||||
$order = array('created_at' => 'DESC');
|
||||
|
||||
$this->db->from($table);
|
||||
|
||||
$search_value = !empty($_POST['search']['value']) ? $_POST['search']['value'] : '';
|
||||
|
||||
// SEARCH
|
||||
if ($search_value != '') {
|
||||
$this->db->group_start();
|
||||
foreach ($column_search as $i => $col_name) {
|
||||
if ($i === 0) {
|
||||
$this->db->like($col_name, $search_value);
|
||||
} else {
|
||||
$this->db->or_like($col_name, $search_value);
|
||||
}
|
||||
}
|
||||
$this->db->group_end();
|
||||
}
|
||||
|
||||
// ORDER
|
||||
if (isset($_POST['order'])) {
|
||||
$col_index = $_POST['order'][0]['column'];
|
||||
$dir = $_POST['order'][0]['dir'];
|
||||
if (isset($column_order[$col_index])) {
|
||||
$this->db->order_by($column_order[$col_index], $dir);
|
||||
}
|
||||
} else {
|
||||
$this->db->order_by(key($order), $order[key($order)]);
|
||||
}
|
||||
|
||||
// PAGINATION
|
||||
if ($_POST['length'] != -1) {
|
||||
$this->db->limit($_POST['length'], $_POST['start']);
|
||||
}
|
||||
|
||||
$query = $this->db->get();
|
||||
$data = [];
|
||||
$no = $_POST['start'];
|
||||
|
||||
foreach ($query->result() as $row) {
|
||||
$no++;
|
||||
|
||||
// Badge for 'status'
|
||||
$statusBadge = '';
|
||||
switch ($row->status) {
|
||||
case 'terkirim': $statusBadge = '<span class="badge bg-success">Terkirim</span>'; break;
|
||||
case 'proses': $statusBadge = '<span class="badge bg-info">Proses</span>'; break;
|
||||
case 'pending': $statusBadge = '<span class="badge bg-warning">Pending</span>'; break;
|
||||
case 'dibaca': $statusBadge = '<span class="badge bg-primary">Dibaca</span>'; break;
|
||||
default: $statusBadge = '<span class="badge bg-secondary">' . htmlspecialchars($row->status) . '</span>'; break;
|
||||
}
|
||||
|
||||
// Type display
|
||||
$typeDisplay = '';
|
||||
switch ($row->type) {
|
||||
case 'wa_official': $typeDisplay = 'WhatsApp Official'; break;
|
||||
case 'wa_unofficial': $typeDisplay = 'WhatsApp Unofficial'; break;
|
||||
case 'email': $typeDisplay = 'Email'; break;
|
||||
default: $typeDisplay = htmlspecialchars($row->type); break;
|
||||
}
|
||||
|
||||
$penerima = !empty($row->nomor_whatsapp) ? htmlspecialchars($row->nomor_whatsapp) : htmlspecialchars($row->email);
|
||||
|
||||
$data[] = [
|
||||
$no,
|
||||
date('d-m-Y H:i:s', strtotime($row->created_at)),
|
||||
$typeDisplay,
|
||||
$penerima,
|
||||
'<div class="truncate-text">' . htmlspecialchars($row->pesan) . '</div>',
|
||||
$statusBadge
|
||||
];
|
||||
}
|
||||
|
||||
// COUNT TOTAL RECORDS
|
||||
$this->db->from($table);
|
||||
if ($search_value != '') {
|
||||
$this->db->group_start();
|
||||
foreach ($column_search as $i => $col_name) {
|
||||
if ($i === 0) {
|
||||
$this->db->like($col_name, $search_value);
|
||||
} else {
|
||||
$this->db->or_like($col_name, $search_value);
|
||||
}
|
||||
}
|
||||
$this->db->group_end();
|
||||
}
|
||||
$recordsFiltered = $this->db->count_all_results();
|
||||
|
||||
$output = [
|
||||
"draw" => intval($_POST['draw']),
|
||||
"recordsTotal" => $this->db->count_all($table),
|
||||
"recordsFiltered" => $recordsFiltered,
|
||||
"data" => $data
|
||||
];
|
||||
|
||||
echo json_encode($output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Qr extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
// Load library QR Code manual
|
||||
require_once APPPATH . 'libraries/phpqrcode/qrlib.php';
|
||||
|
||||
// Cek apakah user sudah login
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('login');
|
||||
}
|
||||
}
|
||||
|
||||
// Tampilkan QR (dengan margin kecil)
|
||||
public function show($text = "contoh")
|
||||
{
|
||||
header("Content-Type: image/png");
|
||||
|
||||
// Param: text, outfile, ECC, size, margin
|
||||
QRcode::png($text, null, QR_ECLEVEL_H, 8, 1);
|
||||
}
|
||||
|
||||
// Download QR Code
|
||||
public function download($text = "contoh")
|
||||
{
|
||||
$fileName = "QR_" . time() . ".png";
|
||||
$tempDir = FCPATH . "downloads/";
|
||||
|
||||
if (!is_dir($tempDir)) {
|
||||
mkdir($tempDir, 0777, true);
|
||||
}
|
||||
|
||||
$filePath = $tempDir . $fileName;
|
||||
|
||||
// Generate QR ke file (margin diperkecil)
|
||||
QRcode::png($text, $filePath, QR_ECLEVEL_H, 8, 1);
|
||||
|
||||
// Force download
|
||||
header('Content-Type: image/png');
|
||||
header('Content-Disposition: attachment; filename="'.$fileName.'"');
|
||||
readfile($filePath);
|
||||
|
||||
// Hapus setelah download
|
||||
unlink($filePath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,644 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Scheduler extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->database();
|
||||
|
||||
date_default_timezone_set('Asia/Jakarta');
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// PROCESS ATTENDANCE LOG
|
||||
// =====================================================
|
||||
public function process_attendance()
|
||||
{
|
||||
echo "PROCESS ATTENDANCE START\n";
|
||||
|
||||
// =============================================
|
||||
// GET PENDING LOG
|
||||
// =============================================
|
||||
$logs = $this->db
|
||||
->where('process_status','pending')
|
||||
->order_by('check_time','ASC')
|
||||
->limit(1000)
|
||||
->get('k_attendance_logs')
|
||||
->result();
|
||||
|
||||
foreach($logs as $log){
|
||||
|
||||
try{
|
||||
|
||||
// =====================================
|
||||
// GET EMPLOYEE
|
||||
// =====================================
|
||||
$employee = $this->db
|
||||
->where(
|
||||
'fingerprint_user_id',
|
||||
$log->user_id
|
||||
)
|
||||
->where('is_active',1)
|
||||
->get('k_employees')
|
||||
->row();
|
||||
|
||||
if(!$employee){
|
||||
|
||||
$this->updateLogStatus(
|
||||
$log->id,
|
||||
'failed'
|
||||
);
|
||||
|
||||
echo "FAILED EMPLOYEE : {$log->user_id}\n";
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// UPDATE EMPLOYEE ID
|
||||
// =====================================
|
||||
$this->db
|
||||
->where('id',$log->id)
|
||||
->update(
|
||||
'k_attendance_logs',
|
||||
[
|
||||
'employee_id' => $employee->id
|
||||
]
|
||||
);
|
||||
|
||||
$logDateTime = date(
|
||||
'Y-m-d H:i:s',
|
||||
strtotime($log->check_time)
|
||||
);
|
||||
|
||||
// =====================================
|
||||
// FIND SCHEDULE
|
||||
// SUPPORT SHIFT MALAM
|
||||
// =====================================
|
||||
$this->db->from(
|
||||
'k_employee_shift_schedules'
|
||||
);
|
||||
|
||||
$this->db->where(
|
||||
'employee_id',
|
||||
$employee->id
|
||||
);
|
||||
|
||||
$this->db->where(
|
||||
'status',
|
||||
'published'
|
||||
);
|
||||
|
||||
// =====================================
|
||||
// RANGE SHIFT
|
||||
// =====================================
|
||||
$this->db->where("
|
||||
'{$logDateTime}' BETWEEN
|
||||
DATE_SUB(start_datetime, INTERVAL 3 HOUR)
|
||||
AND
|
||||
DATE_ADD(end_datetime, INTERVAL 6 HOUR)
|
||||
", null, false);
|
||||
|
||||
$this->db->order_by(
|
||||
'start_datetime',
|
||||
'DESC'
|
||||
);
|
||||
|
||||
$schedule = $this->db->get()->row();
|
||||
|
||||
// =====================================
|
||||
// SCHEDULE NOT FOUND
|
||||
// =====================================
|
||||
if(!$schedule){
|
||||
|
||||
$this->updateLogStatus(
|
||||
$log->id,
|
||||
'failed'
|
||||
);
|
||||
|
||||
echo "FAILED SCHEDULE : {$logDateTime}\n";
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// GET SHIFT
|
||||
// =====================================
|
||||
$shift = $this->db
|
||||
->where('id',$schedule->shift_id)
|
||||
->get('k_shifts')
|
||||
->row();
|
||||
|
||||
if(!$shift){
|
||||
|
||||
$this->updateLogStatus(
|
||||
$log->id,
|
||||
'failed'
|
||||
);
|
||||
|
||||
echo "FAILED SHIFT : {$schedule->shift_id}\n";
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// ATTENDANCE DATE
|
||||
// =====================================
|
||||
$attendance_date = date(
|
||||
'Y-m-d',
|
||||
strtotime($schedule->start_datetime)
|
||||
);
|
||||
|
||||
// =====================================
|
||||
// GET ATTENDANCE
|
||||
// =====================================
|
||||
$attendance = $this->db
|
||||
->where(
|
||||
'employee_id',
|
||||
$employee->id
|
||||
)
|
||||
->where(
|
||||
'attendance_date',
|
||||
$attendance_date
|
||||
)
|
||||
->get('k_attendances')
|
||||
->row();
|
||||
|
||||
// =====================================
|
||||
// CHECK LATE
|
||||
// =====================================
|
||||
$late_minutes = 0;
|
||||
|
||||
$maxCheckin = strtotime(
|
||||
$schedule->start_datetime
|
||||
) + (
|
||||
$shift->late_tolerance_minutes * 60
|
||||
);
|
||||
|
||||
if(
|
||||
strtotime($logDateTime)
|
||||
>
|
||||
$maxCheckin
|
||||
){
|
||||
|
||||
$late_minutes = floor(
|
||||
(
|
||||
strtotime($logDateTime)
|
||||
-
|
||||
strtotime($schedule->start_datetime)
|
||||
) / 60
|
||||
);
|
||||
|
||||
if($late_minutes < 0){
|
||||
$late_minutes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// INSERT CHECKIN
|
||||
// =====================================
|
||||
if(!$attendance){
|
||||
|
||||
$this->db->insert(
|
||||
'k_attendances',
|
||||
[
|
||||
|
||||
'employee_id' => $employee->id,
|
||||
|
||||
'attendance_date' => $attendance_date,
|
||||
|
||||
'checkin_time' => $logDateTime,
|
||||
|
||||
'late_minutes' => $late_minutes,
|
||||
|
||||
'attendance_status' => (
|
||||
$late_minutes > 0
|
||||
? 'late'
|
||||
: 'present'
|
||||
),
|
||||
|
||||
'shift_id' => $shift->id,
|
||||
|
||||
'attendance_log_in_id' => $log->id,
|
||||
|
||||
'created_at' => date('Y-m-d H:i:s')
|
||||
]
|
||||
);
|
||||
|
||||
echo "CHECKIN : {$employee->full_name}\n";
|
||||
|
||||
} else {
|
||||
|
||||
// =================================
|
||||
// SUDAH ADA CHECKOUT
|
||||
// =================================
|
||||
if(!empty($attendance->checkout_time)){
|
||||
|
||||
$this->updateLogStatus(
|
||||
$log->id,
|
||||
'processed'
|
||||
);
|
||||
|
||||
echo "SKIP LOG (SUDAH CHECKOUT)\n";
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// =================================
|
||||
// CEK SELISIH JAM
|
||||
// =================================
|
||||
$diffMinutes = floor(
|
||||
(
|
||||
strtotime($logDateTime)
|
||||
-
|
||||
strtotime($attendance->checkin_time)
|
||||
) / 60
|
||||
);
|
||||
|
||||
// =================================
|
||||
// MINIMAL 2 JAM
|
||||
// BARU DIANGGAP CHECKOUT
|
||||
// =================================
|
||||
if($diffMinutes < 120){
|
||||
|
||||
$this->updateLogStatus(
|
||||
$log->id,
|
||||
'processed'
|
||||
);
|
||||
|
||||
echo "SKIP DUPLICATE LOG : {$employee->full_name}\n";
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// =================================
|
||||
// WORK HOURS
|
||||
// =================================
|
||||
$workHours = (
|
||||
strtotime($logDateTime)
|
||||
-
|
||||
strtotime($attendance->checkin_time)
|
||||
) / 3600;
|
||||
|
||||
if($workHours < 0){
|
||||
$workHours = 0;
|
||||
}
|
||||
|
||||
// =================================
|
||||
// EARLY LEAVE
|
||||
// =================================
|
||||
$early_leave_minutes = 0;
|
||||
|
||||
if(
|
||||
strtotime($logDateTime)
|
||||
<
|
||||
strtotime($schedule->end_datetime)
|
||||
){
|
||||
|
||||
$early_leave_minutes = floor(
|
||||
(
|
||||
strtotime($schedule->end_datetime)
|
||||
-
|
||||
strtotime($logDateTime)
|
||||
) / 60
|
||||
);
|
||||
|
||||
if($early_leave_minutes < 0){
|
||||
$early_leave_minutes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// =================================
|
||||
// OVERTIME
|
||||
// =================================
|
||||
$overtime_hours = 0;
|
||||
|
||||
if(
|
||||
strtotime($logDateTime)
|
||||
>
|
||||
strtotime($schedule->end_datetime)
|
||||
){
|
||||
|
||||
$overtime_hours = round(
|
||||
(
|
||||
strtotime($logDateTime)
|
||||
-
|
||||
strtotime($schedule->end_datetime)
|
||||
) / 3600,
|
||||
2
|
||||
);
|
||||
|
||||
if($overtime_hours < 0){
|
||||
$overtime_hours = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// =================================
|
||||
// UPDATE CHECKOUT
|
||||
// =================================
|
||||
$this->db
|
||||
->where(
|
||||
'id',
|
||||
$attendance->id
|
||||
)
|
||||
->update(
|
||||
'k_attendances',
|
||||
[
|
||||
|
||||
'checkout_time' => $logDateTime,
|
||||
|
||||
'attendance_log_out_id' => $log->id,
|
||||
|
||||
'work_hours' => round($workHours,2),
|
||||
|
||||
'early_leave_minutes' => $early_leave_minutes,
|
||||
|
||||
'overtime_hours' => $overtime_hours
|
||||
]
|
||||
);
|
||||
|
||||
echo "CHECKOUT : {$employee->full_name}\n";
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// UPDATE LOG STATUS
|
||||
// =====================================
|
||||
$this->updateLogStatus(
|
||||
$log->id,
|
||||
'processed'
|
||||
);
|
||||
|
||||
echo "SUCCESS LOG ID : {$log->id}\n";
|
||||
|
||||
} catch(Exception $e){
|
||||
|
||||
$this->updateLogStatus(
|
||||
$log->id,
|
||||
'failed'
|
||||
);
|
||||
|
||||
echo "ERROR : " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "PROCESS ATTENDANCE DONE\n";
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// AUTO CLOSE ATTENDANCE
|
||||
// =====================================================
|
||||
public function auto_close_attendance()
|
||||
{
|
||||
echo "AUTO CLOSE START\n";
|
||||
|
||||
// =============================================
|
||||
// AMBIL ATTENDANCE BELUM CHECKOUT
|
||||
// =============================================
|
||||
$attendances = $this->db
|
||||
->where('checkout_time IS NULL', null, false)
|
||||
->get('k_attendances')
|
||||
->result();
|
||||
|
||||
foreach($attendances as $attendance){
|
||||
|
||||
// =========================================
|
||||
// GET SCHEDULE
|
||||
// =========================================
|
||||
$schedule = $this->db
|
||||
->where(
|
||||
'employee_id',
|
||||
$attendance->employee_id
|
||||
)
|
||||
->where(
|
||||
'shift_id',
|
||||
$attendance->shift_id
|
||||
)
|
||||
->where(
|
||||
'DATE(start_datetime)',
|
||||
$attendance->attendance_date
|
||||
)
|
||||
->get('k_employee_shift_schedules')
|
||||
->row();
|
||||
|
||||
if(!$schedule){
|
||||
continue;
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// AUTO CLOSE
|
||||
// END SHIFT + 4 JAM
|
||||
// =========================================
|
||||
$autoCloseTime = date(
|
||||
'Y-m-d H:i:s',
|
||||
strtotime(
|
||||
$schedule->end_datetime . ' +4 hours'
|
||||
)
|
||||
);
|
||||
|
||||
// =========================================
|
||||
// BELUM WAKTUNYA
|
||||
// =========================================
|
||||
if(
|
||||
strtotime(date('Y-m-d H:i:s'))
|
||||
<
|
||||
strtotime($autoCloseTime)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// WORK HOURS
|
||||
// =========================================
|
||||
$workHours = (
|
||||
strtotime($schedule->end_datetime)
|
||||
-
|
||||
strtotime($attendance->checkin_time)
|
||||
) / 3600;
|
||||
|
||||
if($workHours < 0){
|
||||
$workHours = 0;
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// AUTO CHECKOUT
|
||||
// =========================================
|
||||
$this->db
|
||||
->where('id',$attendance->id)
|
||||
->update(
|
||||
'k_attendances',
|
||||
[
|
||||
|
||||
'checkout_time' => $schedule->end_datetime,
|
||||
|
||||
'work_hours' => round($workHours,2),
|
||||
|
||||
'notes' => 'Auto checkout by system'
|
||||
]
|
||||
);
|
||||
|
||||
echo "AUTO CLOSE EMPLOYEE : {$attendance->employee_id}\n";
|
||||
}
|
||||
|
||||
echo "AUTO CLOSE DONE\n";
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// GENERATE DAILY ATTENDANCE
|
||||
// =====================================================
|
||||
public function generate_daily_attendance()
|
||||
{
|
||||
echo "GENERATE DAILY START\n";
|
||||
|
||||
// =============================================
|
||||
// GENERATE HARI KEMARIN
|
||||
// =============================================
|
||||
$date = date(
|
||||
'Y-m-d',
|
||||
strtotime('-1 day')
|
||||
);
|
||||
|
||||
// =============================================
|
||||
// GET ALL SCHEDULE
|
||||
// =============================================
|
||||
$schedules = $this->db
|
||||
->where('schedule_date', $date)
|
||||
->where('status','published')
|
||||
->get('k_employee_shift_schedules')
|
||||
->result();
|
||||
|
||||
foreach($schedules as $schedule){
|
||||
|
||||
// =========================================
|
||||
// CHECK ATTENDANCE EXIST
|
||||
// =========================================
|
||||
$attendance = $this->db
|
||||
->where(
|
||||
'employee_id',
|
||||
$schedule->employee_id
|
||||
)
|
||||
->where(
|
||||
'attendance_date',
|
||||
$date
|
||||
)
|
||||
->get('k_attendances')
|
||||
->row();
|
||||
|
||||
if($attendance){
|
||||
continue;
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// CHECK HOLIDAY
|
||||
// =========================================
|
||||
$holiday = $this->db
|
||||
->where('holiday_date',$date)
|
||||
->get('k_holidays')
|
||||
->row();
|
||||
|
||||
if($holiday){
|
||||
|
||||
$this->db->insert(
|
||||
'k_attendances',
|
||||
[
|
||||
|
||||
'employee_id' => $schedule->employee_id,
|
||||
|
||||
'attendance_date' => $date,
|
||||
|
||||
'attendance_status' => 'holiday',
|
||||
|
||||
'is_holiday' => 1,
|
||||
|
||||
'shift_id' => $schedule->shift_id,
|
||||
|
||||
'notes' => $holiday->holiday_name
|
||||
]
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// CHECK LEAVE
|
||||
// =========================================
|
||||
$leave = $this->db
|
||||
->where(
|
||||
'employee_id',
|
||||
$schedule->employee_id
|
||||
)
|
||||
->where(
|
||||
'approval_status',
|
||||
'approved'
|
||||
)
|
||||
->where('start_date <=',$date)
|
||||
->where('end_date >=',$date)
|
||||
->get('k_leave_requests')
|
||||
->row();
|
||||
|
||||
if($leave){
|
||||
|
||||
$this->db->insert(
|
||||
'k_attendances',
|
||||
[
|
||||
|
||||
'employee_id' => $schedule->employee_id,
|
||||
|
||||
'attendance_date' => $date,
|
||||
|
||||
'attendance_status' => $leave->leave_type,
|
||||
|
||||
'shift_id' => $schedule->shift_id,
|
||||
|
||||
'notes' => $leave->reason
|
||||
]
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// DEFAULT ALPHA
|
||||
// =========================================
|
||||
$this->db->insert(
|
||||
'k_attendances',
|
||||
[
|
||||
|
||||
'employee_id' => $schedule->employee_id,
|
||||
|
||||
'attendance_date' => $date,
|
||||
|
||||
'attendance_status' => 'alpha',
|
||||
|
||||
'shift_id' => $schedule->shift_id,
|
||||
|
||||
'notes' => 'Tidak hadir'
|
||||
]
|
||||
);
|
||||
|
||||
echo "GENERATE EMPLOYEE : {$schedule->employee_id}\n";
|
||||
}
|
||||
|
||||
echo "GENERATE DAILY DONE\n";
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// UPDATE LOG STATUS
|
||||
// =====================================================
|
||||
private function updateLogStatus(
|
||||
$id,
|
||||
$status
|
||||
){
|
||||
|
||||
$this->db
|
||||
->where('id',$id)
|
||||
->update(
|
||||
'k_attendance_logs',
|
||||
[
|
||||
'process_status' => $status
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Setting extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// Cek apakah user sudah login
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('login');
|
||||
}
|
||||
|
||||
if (!check_permission('setting', 'can_view')) {
|
||||
show_error('Anda tidak memiliki izin untuk mengakses halaman ini.', 403);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================
|
||||
// MAIN PAGE
|
||||
// ==========================
|
||||
public function index()
|
||||
{
|
||||
if (!check_permission('setting', 'can_view')) {
|
||||
show_error('Tidak memiliki izin untuk melihat detail.', 403);
|
||||
}
|
||||
|
||||
// Ambil config id=1
|
||||
$cfg = $this->db->get_where("config", ["id" => 1])->row();
|
||||
|
||||
// Jika tidak ada data config
|
||||
$config = $cfg ?: $this->defaultConfig();
|
||||
|
||||
// Ambil template pesan
|
||||
$template_pesan = $this->db
|
||||
->order_by("id", "ASC")
|
||||
->get("template_pesan")
|
||||
->result();
|
||||
|
||||
$data = [
|
||||
"active_menu" => "pengaturan",
|
||||
"config" => $config,
|
||||
"template_pesan" => $template_pesan
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('setting/layout', $data);
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// DEFAULT CONFIG
|
||||
// ===============================
|
||||
private function defaultConfig()
|
||||
{
|
||||
if (!check_permission('setting', 'can_view')) {
|
||||
show_error('Tidak memiliki izin untuk melihat detail.', 403);
|
||||
}
|
||||
|
||||
return (object)[
|
||||
"nama_lembaga" => "",
|
||||
"pimpinan_lembaga" => "",
|
||||
"card_background" => "",
|
||||
"card_orientation" => "landscape",
|
||||
"wa_mode" => "official",
|
||||
"wa_phone" => "",
|
||||
"wa_phone_id" => "",
|
||||
"wa_waba_id" => "",
|
||||
"wa_access_token" => "",
|
||||
"wa_endpoint" => "",
|
||||
"wa_api_key" => ""
|
||||
];
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// 1. SIMPAN SETTING UMUM
|
||||
// ===============================
|
||||
public function save_umum()
|
||||
{
|
||||
if (!check_permission('setting', 'can_view')) {
|
||||
show_error('Tidak memiliki izin untuk melihat detail.', 403);
|
||||
}
|
||||
|
||||
$update = [
|
||||
"nama_lembaga" => $this->input->post("nama_lembaga"),
|
||||
"pimpinan_lembaga" => $this->input->post("pimpinan_lembaga"),
|
||||
"updated_at" => date("Y-m-d H:i:s")
|
||||
];
|
||||
|
||||
$this->db->where("id", 1)->update("config", $update);
|
||||
|
||||
redirect("setting");
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// 2. SIMPAN CARD + UPLOAD BG
|
||||
// ===============================
|
||||
public function save_card()
|
||||
{
|
||||
|
||||
if (!check_permission('setting', 'can_view')) {
|
||||
show_error('Tidak memiliki izin untuk melihat detail.', 403);
|
||||
}
|
||||
|
||||
$orientation = $this->input->post("card_orientation");
|
||||
$bg = null;
|
||||
|
||||
// Jika ada upload file
|
||||
if (!empty($_FILES["card_background"]["name"])) {
|
||||
|
||||
$config['upload_path'] = './uploads/card/';
|
||||
$config['allowed_types'] = 'jpg|jpeg|png';
|
||||
$config['file_name'] = 'background_' . time();
|
||||
|
||||
if (!is_dir('./uploads/card/')) {
|
||||
mkdir('./uploads/card/', 0777, true);
|
||||
}
|
||||
|
||||
$this->load->library('upload', $config);
|
||||
|
||||
if ($this->upload->do_upload('card_background')) {
|
||||
$file = $this->upload->data();
|
||||
$bg = "uploads/card/" . $file['file_name'];
|
||||
}
|
||||
}
|
||||
|
||||
// Data update
|
||||
$data = [
|
||||
"card_orientation" => $orientation,
|
||||
"updated_at" => date("Y-m-d H:i:s")
|
||||
];
|
||||
|
||||
// Jika ada gambar baru
|
||||
if ($bg !== null) {
|
||||
$data["card_background"] = $bg;
|
||||
}
|
||||
|
||||
$this->db->where("id", 1)->update("config", $data);
|
||||
|
||||
redirect("setting");
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// 3. SIMPAN SETTING WHATSAPP
|
||||
// ===============================
|
||||
public function save_whatsapp()
|
||||
{
|
||||
|
||||
if (!check_permission('setting', 'can_view')) {
|
||||
show_error('Tidak memiliki izin untuk melihat detail.', 403);
|
||||
}
|
||||
|
||||
$mode = $this->input->post("wa_mode");
|
||||
|
||||
$data = [
|
||||
"wa_mode" => $mode,
|
||||
"updated_at" => date("Y-m-d H:i:s")
|
||||
];
|
||||
|
||||
if ($mode == "official") {
|
||||
|
||||
$data["wa_phone"] = $this->input->post("wa_phone");
|
||||
$data["wa_phone_id"] = $this->input->post("wa_phone_id");
|
||||
$data["wa_waba_id"] = $this->input->post("wa_waba_id");
|
||||
$data["wa_access_token"] = $this->input->post("wa_access_token");
|
||||
|
||||
// Kosongkan unofficial
|
||||
$data["wa_endpoint"] = "";
|
||||
$data["wa_api_key"] = "";
|
||||
|
||||
} else {
|
||||
|
||||
$data["wa_endpoint"] = $this->input->post("wa_endpoint");
|
||||
$data["wa_api_key"] = $this->input->post("wa_api_key");
|
||||
|
||||
// Kosongkan official
|
||||
$data["wa_phone"] = "";
|
||||
$data["wa_phone_id"] = "";
|
||||
$data["wa_waba_id"] = "";
|
||||
$data["wa_access_token"] = "";
|
||||
}
|
||||
|
||||
$this->db->where("id", 1)->update("config", $data);
|
||||
|
||||
redirect("setting");
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// 4. UPDATE TEMPLATE PESAN
|
||||
// ===============================
|
||||
public function update_template_pesan()
|
||||
{
|
||||
|
||||
if (!check_permission('setting', 'can_view')) {
|
||||
show_error('Tidak memiliki izin untuk melihat detail.', 403);
|
||||
}
|
||||
|
||||
$data = [
|
||||
"nama_template" => $this->input->post("nama_template"),
|
||||
"isi_template" => $this->input->post("isi_template")
|
||||
];
|
||||
|
||||
$id = $this->input->post("id");
|
||||
|
||||
$this->db->where("id", $id)->update("template_pesan", $data);
|
||||
|
||||
redirect("setting");
|
||||
}
|
||||
|
||||
public function cek_whatsapp_status()
|
||||
{
|
||||
|
||||
if (!check_permission('setting', 'can_view')) {
|
||||
show_error('Tidak memiliki izin untuk melihat detail.', 403);
|
||||
}
|
||||
|
||||
$config = $this->db->get_where("config", ["id" => 1])->row();
|
||||
|
||||
if (!$config) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"img" => base_url("uploads/whatsapp/disconnect.png"),
|
||||
"msg" => "Config tidak ditemukan"
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fungsi bantu call API
|
||||
function callCurl($url, $fields)
|
||||
{
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT => 0,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_CUSTOMREQUEST => 'GET',
|
||||
CURLOPT_POSTFIELDS => $fields,
|
||||
CURLOPT_HTTPHEADER => array( 'Content-Type: application/x-www-form-urlencoded' ),
|
||||
]);
|
||||
$response = curl_exec($curl);
|
||||
curl_close($curl);
|
||||
return $response;
|
||||
}
|
||||
|
||||
// 1. CEK STATUS
|
||||
$response = callCurl(
|
||||
$config->wa_endpoint . "getState",
|
||||
"apiKey=" . $config->wa_api_key
|
||||
);
|
||||
|
||||
$data = json_decode($response, true);
|
||||
|
||||
if (!$data || !isset($data['results']['state'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"img" => base_url('uploads/whatsapp/disconnect.png'),
|
||||
"msg" => "Gagal membaca respon server WA",
|
||||
"data" => $data,
|
||||
"url_key" => $config->wa_endpoint . ' ' . $config->wa_api_key
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$state = $data['results']['state'];
|
||||
|
||||
// ==========================================================
|
||||
// 1. CONNECTED → tampilkan gambar connected
|
||||
// ==========================================================
|
||||
if ($state == "CONNECTED") {
|
||||
echo json_encode([
|
||||
"status" => "CONNECTED",
|
||||
"img" => base_url('uploads/whatsapp/connect.png')
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
// 2. SERVICE_OFF → tampilkan disconnect + mulai service
|
||||
// ==========================================================
|
||||
if ($state == "SERVICE_OFF") {
|
||||
|
||||
// Mulai service
|
||||
callCurl(
|
||||
$config->wa_endpoint . "serviceStart",
|
||||
"apiKey=" . $config->wa_api_key
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
"status" => "SERVICE_OFF",
|
||||
"img" => base_url('uploads/whatsapp/disconnect.png')
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
// 3. SERVICE_SCAN → ambil QR
|
||||
// ==========================================================
|
||||
if ($state == "SERVICE_SCAN") {
|
||||
|
||||
$responseQR = callCurl(
|
||||
$config->wa_endpoint . "getQR",
|
||||
"apiKey=" . $config->wa_api_key
|
||||
);
|
||||
|
||||
$qrData = json_decode($responseQR, true);
|
||||
|
||||
if (!isset($qrData['results']['qrString'])) {
|
||||
echo json_encode([
|
||||
"status" => "SERVICE_SCAN",
|
||||
"img" => base_url('uploads/whatsapp/map_loader.gif')
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"status" => "SERVICE_SCAN",
|
||||
"img" => $qrData['results']['qrString']
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
// 4. STATUS LAIN → tampilkan loader
|
||||
// ==========================================================
|
||||
echo json_encode([
|
||||
"status" => "UNKNOWN",
|
||||
"img" => base_url('uploads/whatsapp/map_loader.gif')
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Shifts extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->database();
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// PAGE
|
||||
// ==========================================
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
"active_menu" => "shift"
|
||||
];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('employees/shift');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// DATATABLE
|
||||
// =====================================================
|
||||
public function get_data()
|
||||
{
|
||||
$list = $this->db
|
||||
->order_by('id','DESC')
|
||||
->get('k_shifts')
|
||||
->result();
|
||||
|
||||
$data = [];
|
||||
$no = 1;
|
||||
|
||||
foreach($list as $r){
|
||||
|
||||
$night = $r->is_night_shift == 1
|
||||
? '<span class="badge bg-dark">Night Shift</span>'
|
||||
: '<span class="badge bg-success">Normal</span>';
|
||||
|
||||
$data[] = [
|
||||
$no++,
|
||||
$r->shift_code,
|
||||
$r->shift_name,
|
||||
$r->checkin_time,
|
||||
$r->checkout_time,
|
||||
$r->late_tolerance_minutes . ' Menit',
|
||||
$r->work_hours . ' Jam',
|
||||
$night,
|
||||
'
|
||||
<button class="btn btn-warning btn-sm btn-edit"
|
||||
data-id="'.$r->id.'">
|
||||
Edit
|
||||
</button>
|
||||
|
||||
<button class="btn btn-danger btn-sm btn-delete"
|
||||
data-id="'.$r->id.'">
|
||||
Delete
|
||||
</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"data" => $data
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// DETAIL
|
||||
// =====================================================
|
||||
public function detail($id)
|
||||
{
|
||||
$data = $this->db
|
||||
->get_where('k_shifts',['id'=>$id])
|
||||
->row();
|
||||
|
||||
echo json_encode($data);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// SAVE
|
||||
// =====================================================
|
||||
public function save()
|
||||
{
|
||||
$data = [
|
||||
'shift_code' => $this->input->post('shift_code'),
|
||||
'shift_name' => $this->input->post('shift_name'),
|
||||
'checkin_time' => $this->input->post('checkin_time'),
|
||||
'checkout_time' => $this->input->post('checkout_time'),
|
||||
'late_tolerance_minutes' => $this->input->post('late_tolerance_minutes'),
|
||||
'work_hours' => $this->input->post('work_hours'),
|
||||
'is_night_shift' => $this->input->post('is_night_shift')
|
||||
];
|
||||
|
||||
$this->db->insert('k_shifts',$data);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message'=> 'Shift berhasil ditambahkan'
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// UPDATE
|
||||
// =====================================================
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
|
||||
$data = [
|
||||
'shift_code' => $this->input->post('shift_code'),
|
||||
'shift_name' => $this->input->post('shift_name'),
|
||||
'checkin_time' => $this->input->post('checkin_time'),
|
||||
'checkout_time' => $this->input->post('checkout_time'),
|
||||
'late_tolerance_minutes' => $this->input->post('late_tolerance_minutes'),
|
||||
'work_hours' => $this->input->post('work_hours'),
|
||||
'is_night_shift' => $this->input->post('is_night_shift')
|
||||
];
|
||||
|
||||
$this->db->where('id',$id);
|
||||
$this->db->update('k_shifts',$data);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message'=> 'Shift berhasil diupdate'
|
||||
]);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// DELETE
|
||||
// =====================================================
|
||||
public function delete($id)
|
||||
{
|
||||
$this->db->delete('k_shifts',['id'=>$id]);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message'=> 'Shift berhasil dihapus'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Users extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->load->model('DynamicModel', 'dm');
|
||||
$this->load->library('form_validation');
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
||||
if($this->session->userdata('role') != 'Admin'){
|
||||
show_error('Akses ditolak', 403);
|
||||
}
|
||||
|
||||
$data = ["active_menu" => "users"];
|
||||
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('users/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DATATABLE USERS + ROLES
|
||||
// =========================
|
||||
public function get_data()
|
||||
{
|
||||
$this->db->select('
|
||||
users.id,
|
||||
users.username,
|
||||
users.nama,
|
||||
roles.nama_role
|
||||
');
|
||||
$this->db->from('users');
|
||||
$this->db->join('roles', 'roles.id = users.role_id', 'left');
|
||||
|
||||
$column_order = ['users.id', 'users.username', 'users.nama', 'roles.nama_role'];
|
||||
$column_search = ['users.username', 'users.nama', 'roles.nama_role'];
|
||||
$order = ['users.id' => 'DESC'];
|
||||
|
||||
$search_value = $this->input->post('search')['value'] ?? '';
|
||||
|
||||
if (!empty($search_value)) {
|
||||
$this->db->group_start();
|
||||
foreach ($column_search as $i => $col) {
|
||||
if ($i === 0) {
|
||||
$this->db->like($col, $search_value);
|
||||
} else {
|
||||
$this->db->or_like($col, $search_value);
|
||||
}
|
||||
}
|
||||
$this->db->group_end();
|
||||
}
|
||||
|
||||
if ($this->input->post('order')) {
|
||||
$col_index = $this->input->post('order')[0]['column'];
|
||||
$dir = $this->input->post('order')[0]['dir'];
|
||||
|
||||
if (isset($column_order[$col_index])) {
|
||||
$this->db->order_by($column_order[$col_index], $dir);
|
||||
}
|
||||
} else {
|
||||
$this->db->order_by(key($order), $order[key($order)]);
|
||||
}
|
||||
|
||||
if ($this->input->post('length') != -1) {
|
||||
$this->db->limit(
|
||||
$this->input->post('length'),
|
||||
$this->input->post('start')
|
||||
);
|
||||
}
|
||||
|
||||
$query = $this->db->get();
|
||||
$data = $query->result();
|
||||
|
||||
$output = [
|
||||
"draw" => intval($this->input->post('draw')),
|
||||
"recordsTotal" => $this->db->count_all('users'),
|
||||
"recordsFiltered" => $this->_count_filtered($search_value),
|
||||
"data" => []
|
||||
];
|
||||
|
||||
foreach ($data as $row) {
|
||||
|
||||
$action = '
|
||||
<button class="btn btn-sm btn-warning btn-edit" data-id="'.$row->id.'">Edit</button>
|
||||
<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Hapus</button>
|
||||
';
|
||||
|
||||
$output['data'][] = [
|
||||
$row->id,
|
||||
$row->username,
|
||||
$row->nama,
|
||||
$row->nama_role,
|
||||
$action
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode($output);
|
||||
}
|
||||
|
||||
private function _count_filtered($search_value)
|
||||
{
|
||||
$this->db->from('users');
|
||||
$this->db->join('roles', 'roles.id = users.role_id', 'left');
|
||||
|
||||
if (!empty($search_value)) {
|
||||
$this->db->group_start();
|
||||
$this->db->like('users.username', $search_value);
|
||||
$this->db->or_like('users.nama', $search_value);
|
||||
$this->db->or_like('roles.nama_role', $search_value);
|
||||
$this->db->group_end();
|
||||
}
|
||||
|
||||
return $this->db->count_all_results();
|
||||
}
|
||||
|
||||
// =========================
|
||||
// STORE USER
|
||||
// =========================
|
||||
public function store()
|
||||
{
|
||||
$this->form_validation->set_rules('username', 'Username', 'required|is_unique[users.username]');
|
||||
$this->form_validation->set_rules('nama', 'Nama', 'required');
|
||||
$this->form_validation->set_rules('role_id', 'Role', 'required');
|
||||
$this->form_validation->set_rules('password', 'Password', 'required|min_length[6]');
|
||||
|
||||
if ($this->form_validation->run() == FALSE) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => validation_errors()
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'username' => $this->input->post('username'),
|
||||
'nama' => $this->input->post('nama'),
|
||||
'role_id' => $this->input->post('role_id'),
|
||||
'password' => password_hash($this->input->post('password'), PASSWORD_DEFAULT)
|
||||
];
|
||||
|
||||
$this->dm->setTable('users')->insert($data);
|
||||
|
||||
log_activity(
|
||||
'users',
|
||||
'create',
|
||||
'Menambahkan user: ' . $data['username'],
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'User berhasil ditambahkan'
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// EDIT USER
|
||||
// =========================
|
||||
public function edit($id)
|
||||
{
|
||||
$user = $this->db->get_where('users', ['id' => $id])->row();
|
||||
|
||||
if ($user) {
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'data' => $user
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => 'User tidak ditemukan'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================
|
||||
// UPDATE USER
|
||||
// =========================
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
|
||||
$this->form_validation->set_rules('username', 'Username', 'required');
|
||||
$this->form_validation->set_rules('nama', 'Nama', 'required');
|
||||
$this->form_validation->set_rules('role_id', 'Role', 'required');
|
||||
|
||||
if (!empty($this->input->post('password'))) {
|
||||
$this->form_validation->set_rules('password', 'Password', 'min_length[6]');
|
||||
}
|
||||
|
||||
if ($this->form_validation->run() == FALSE) {
|
||||
echo json_encode([
|
||||
'status' => false,
|
||||
'message' => validation_errors()
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'username' => $this->input->post('username'),
|
||||
'nama' => $this->input->post('nama'),
|
||||
'role_id' => $this->input->post('role_id')
|
||||
];
|
||||
|
||||
if (!empty($this->input->post('password'))) {
|
||||
$data['password'] = password_hash($this->input->post('password'), PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
$this->dm->setTable('users')->update($id, $data);
|
||||
|
||||
log_activity(
|
||||
'users',
|
||||
'update',
|
||||
'Update user ID: ' . $id . ' username: ' . $this->input->post('username'),
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'User berhasil diupdate'
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DELETE USER
|
||||
// =========================
|
||||
public function delete($id)
|
||||
{
|
||||
$this->dm->setTable('users')->delete($id);
|
||||
|
||||
log_activity(
|
||||
'users',
|
||||
'delete',
|
||||
'Hapus user ID: ' . $id,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => true,
|
||||
'message' => 'User berhasil dihapus'
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET ROLES
|
||||
// =========================
|
||||
public function get_role()
|
||||
{
|
||||
$roles = $this->db->get('roles')->result();
|
||||
|
||||
echo json_encode($roles);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Warehouses extends CI_Controller {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!$this->session->userdata('logged_in')) {
|
||||
redirect('auth');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data = ["active_menu" => "warehouses"];
|
||||
$this->load->view('partials/header', $data);
|
||||
$this->load->view('warehouses/layout');
|
||||
$this->load->view('partials/footer');
|
||||
}
|
||||
|
||||
// =========================
|
||||
// GET DATA (DATATABLE)
|
||||
// =========================
|
||||
public function get_data()
|
||||
{
|
||||
$data = $this->db->get('warehouses')->result();
|
||||
|
||||
$result = [];
|
||||
$no = 1;
|
||||
|
||||
foreach ($data as $row) {
|
||||
$result[] = [
|
||||
$no++,
|
||||
$row->nama,
|
||||
'
|
||||
<button class="btn btn-sm btn-secondary btn-editgudang" data-id="'.$row->id.'">Edit</button>
|
||||
<button class="btn btn-sm btn-danger btn-delete" data-id="'.$row->id.'">Delete</button>
|
||||
'
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode(["data"=>$result]);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DETAIL
|
||||
// =========================
|
||||
public function detail($id)
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->get_where('warehouses',['id'=>$id])->row()
|
||||
);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// SAVE
|
||||
// =========================
|
||||
public function save()
|
||||
{
|
||||
$nama = $this->input->post('nama');
|
||||
|
||||
if(!$nama){
|
||||
echo json_encode(['status'=>false,'message'=>'Nama wajib diisi']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->insert('warehouses', [
|
||||
'nama' => $nama
|
||||
]);
|
||||
|
||||
log_activity(
|
||||
'kode_barang',
|
||||
'create',
|
||||
'Tambah gudang '.$nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Gudang berhasil ditambahkan']);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// UPDATE
|
||||
// =========================
|
||||
public function update()
|
||||
{
|
||||
$id = $this->input->post('id');
|
||||
$nama = $this->input->post('nama');
|
||||
|
||||
if(!$nama){
|
||||
echo json_encode(['status'=>false,'message'=>'Nama wajib diisi']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->where('id',$id)->update('warehouses', [
|
||||
'nama' => $nama
|
||||
]);
|
||||
|
||||
log_activity(
|
||||
'kode_barang',
|
||||
'update',
|
||||
'Update gudang '.$nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Gudang berhasil diupdate']);
|
||||
}
|
||||
|
||||
// =========================
|
||||
// DELETE
|
||||
// =========================
|
||||
public function delete($id)
|
||||
{
|
||||
// optional: cek relasi ke items
|
||||
$cek = $this->db->get_where('items',['warehouse_id'=>$id])->num_rows();
|
||||
|
||||
if($cek > 0){
|
||||
echo json_encode([
|
||||
'status'=>false,
|
||||
'message'=>'Gudang tidak bisa dihapus karena masih dipakai item'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->delete('warehouses',['id'=>$id]);
|
||||
|
||||
log_activity(
|
||||
'kode_barang',
|
||||
'delete',
|
||||
'Delete gudang '.$nama,
|
||||
'success'
|
||||
);
|
||||
|
||||
echo json_encode(['status'=>true,'message'=>'Gudang berhasil dihapus']);
|
||||
}
|
||||
|
||||
|
||||
public function list()
|
||||
{
|
||||
echo json_encode(
|
||||
$this->db->get('warehouses')->result()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class Welcome extends CI_Controller {
|
||||
|
||||
/**
|
||||
* Index Page for this controller.
|
||||
*
|
||||
* Maps to the following URL
|
||||
* http://example.com/index.php/welcome
|
||||
* - or -
|
||||
* http://example.com/index.php/welcome/index
|
||||
* - or -
|
||||
* Since this controller is set as the default controller in
|
||||
* config/routes.php, it's displayed at http://example.com/
|
||||
*
|
||||
* So any other public methods not prefixed with an underscore will
|
||||
* map to /index.php/welcome/<method_name>
|
||||
* @see https://codeigniter.com/userguide3/general/urls.html
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->load->view('login');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
|
||||
function log_activity($module, $action, $desc, $status = 'success')
|
||||
{
|
||||
$CI =& get_instance();
|
||||
|
||||
$ip = $CI->input->ip_address();
|
||||
|
||||
if (!$ip || $ip == '0.0.0.0') {
|
||||
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ??
|
||||
$_SERVER['REMOTE_ADDR'] ??
|
||||
'UNKNOWN';
|
||||
}
|
||||
|
||||
$CI->db->insert('activity_logs', [
|
||||
'user_id' => $CI->session->userdata('user_id') ?? 0,
|
||||
'module' => strtolower($module),
|
||||
'action' => strtolower($action),
|
||||
'description' => $desc,
|
||||
'status' => strtolower($status),
|
||||
'ip_address' => $ip,
|
||||
'created_at' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
if (!function_exists('tanggal_indo')) {
|
||||
function tanggal_indo($tanggal, $format = 'd F Y')
|
||||
{
|
||||
if (empty($tanggal) || $tanggal == '0000-00-00') {
|
||||
return '-';
|
||||
}
|
||||
|
||||
$bulan = [
|
||||
1 => 'Januari',
|
||||
'Februari',
|
||||
'Maret',
|
||||
'April',
|
||||
'Mei',
|
||||
'Juni',
|
||||
'Juli',
|
||||
'Agustus',
|
||||
'September',
|
||||
'Oktober',
|
||||
'November',
|
||||
'Desember'
|
||||
];
|
||||
|
||||
$timestamp = strtotime($tanggal);
|
||||
|
||||
$hari = date('d', $timestamp);
|
||||
$bulan_index = (int)date('m', $timestamp);
|
||||
$tahun = date('Y', $timestamp);
|
||||
|
||||
return $hari . ' ' . $bulan[$bulan_index] . ' ' . $tahun;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Cek permission user
|
||||
* @param string $key => nama fitur (misal: 'siswa', 'dashboard')
|
||||
* @param string $action => action yang dicek (misal: 'can_view', 'can_export')
|
||||
* @return bool
|
||||
*/
|
||||
function check_permission($key, $action = 'can_view') {
|
||||
$CI =& get_instance();
|
||||
$permissions = $CI->session->userdata('permissions');
|
||||
|
||||
if (!$permissions || !is_array($permissions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pastikan key ada
|
||||
if (!isset($permissions[$key])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Jika value berupa array (multiple permissions), cek dengan in_array
|
||||
if (is_array($permissions[$key])) {
|
||||
return in_array($action, $permissions[$key]);
|
||||
}
|
||||
|
||||
// Jika value berupa string tunggal
|
||||
return $permissions[$key] === $action;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
// require_once(APPPATH.'libraries/fpdf/fpdf.php');
|
||||
|
||||
require_once(APPPATH.'third_party/fpdf/fpdf.php');
|
||||
|
||||
class PDF extends FPDF
|
||||
{
|
||||
private $maxWidth = 190;
|
||||
private $nama;
|
||||
private $alamat;
|
||||
private $telepon;
|
||||
private $logo;
|
||||
|
||||
public function setHeaderData($nama, $alamat, $telepon, $logo='')
|
||||
{
|
||||
$this->nama = $nama;
|
||||
$this->alamat = $alamat;
|
||||
$this->telepon = $telepon;
|
||||
$this->logo = $logo;
|
||||
}
|
||||
|
||||
function Header()
|
||||
{
|
||||
// Logo
|
||||
$this->Image($this->logo, 10, 8, 22, 22); // Path ke logo Anda, x, y, width
|
||||
$this->SetXY(35, 11);
|
||||
$this->SetFont('Arial', 'B', 14);
|
||||
$this->Cell(0, 6, $this->nama, 0, 1, 'L');
|
||||
$this->SetFont('Arial', 'I', 10);
|
||||
$this->SetXY(35, 17);
|
||||
$this->Cell(0, 6, $this->alamat, 0, 1, 'L');
|
||||
$this->SetXY(35, 23);
|
||||
$this->Cell(0, 6, 'Phone: '.$this->telepon, 0, 1, 'L');
|
||||
$this->Ln(14);
|
||||
|
||||
// Garis Horizontal
|
||||
$this->SetLineWidth(0.8); // Ketebalan garis
|
||||
$this->Line(10, 33, 200, 33); // x1, y1, x2, y2 (x1, y1 = start; x2, y2 = end)
|
||||
$this->SetLineWidth(0.4);
|
||||
$this->Line(10, 34, 200, 34);
|
||||
|
||||
$this->SetTextColor(255, 140, 0);
|
||||
$this->SetFont('Arial', 'B', 20);
|
||||
$this->Cell(0, -56, 'INVOICE', 0, 1, 'R');
|
||||
$this->Ln(50);
|
||||
}
|
||||
|
||||
function Footer()
|
||||
{
|
||||
$this->SetY(-15);
|
||||
$this->SetFont('Arial', 'I', 8);
|
||||
$this->Cell(0, 10, 'Page ' . $this->PageNo(), 0, 0, 'C');
|
||||
}
|
||||
|
||||
function CustomerDetails($customerName, $customerAddress, $invoiceNumber, $invoiceDate, $customerNumber, $invoiceLimit)
|
||||
{
|
||||
$this->SetFont('Arial', 'B', 11);
|
||||
$this->Cell(0, 6, 'Bill To:', 0, 1);
|
||||
$this->SetFont('Arial', '', 11);
|
||||
$this->Cell(0, 6, $customerName, 0, 1);
|
||||
$this->MultiCell(0, 7, $customerAddress);
|
||||
$this->Cell(0, 6, $customerNumber, 0, 1);
|
||||
$this->Ln(10);
|
||||
|
||||
$this->SetFont('Arial', '', 11);
|
||||
$this->SetXY(140, 37);
|
||||
$this->Cell(0, 6, "No Invoice : $invoiceNumber", 0, 1);
|
||||
$this->SetXY(140, 44);
|
||||
$this->Cell(0, 6, "Invoice Date : $invoiceDate", 0, 1);
|
||||
$this->SetXY(140, 51);
|
||||
$this->Cell(0, 6, "Limit Invoice : $invoiceLimit", 0, 1);
|
||||
$this->Ln(10);
|
||||
}
|
||||
|
||||
function InvoiceTable($header, $data)
|
||||
{
|
||||
// 🔥 7 kolom sekarang
|
||||
$columnWidths = array(8, 22, 30, 70, 15, 20, 25);
|
||||
$totalWidth = array_sum($columnWidths);
|
||||
|
||||
// scaling biar tetap muat
|
||||
$scalingFactor = $this->maxWidth / $totalWidth;
|
||||
|
||||
// header style
|
||||
$this->SetFillColor(255, 140, 0);
|
||||
$this->SetFont('Arial', '', 10);
|
||||
|
||||
// ================= HEADER =================
|
||||
for ($i = 0; $i < count($header); $i++) {
|
||||
$this->Cell($columnWidths[$i] * $scalingFactor, 8, $header[$i], 1, 0, 'C', true);
|
||||
}
|
||||
$this->Ln();
|
||||
|
||||
// ================= DATA =================
|
||||
$this->SetFont('Arial', '', 10);
|
||||
|
||||
foreach ($data as $row) {
|
||||
|
||||
// hitung multiline
|
||||
$nbDesc = $this->NbLines($columnWidths[2] * $scalingFactor, $row[2]);
|
||||
$nbKet = $this->NbLines($columnWidths[3] * $scalingFactor, $row[3]);
|
||||
|
||||
$maxHeight = 8 * max($nbDesc, $nbKet);
|
||||
|
||||
// pagination
|
||||
if ($this->GetY() + $maxHeight > $this->PageBreakTrigger) {
|
||||
$this->AddPage();
|
||||
|
||||
$this->SetFillColor(255, 140, 0);
|
||||
$this->SetFont('Arial', '', 10);
|
||||
|
||||
for ($i = 0; $i < count($header); $i++) {
|
||||
$this->Cell($columnWidths[$i] * $scalingFactor, 8, $header[$i], 1, 0, 'C', true);
|
||||
}
|
||||
$this->Ln();
|
||||
|
||||
$this->SetFont('Arial', '', 10);
|
||||
}
|
||||
|
||||
$x = $this->GetX();
|
||||
$y = $this->GetY();
|
||||
|
||||
// 1. No
|
||||
$this->Cell($columnWidths[0] * $scalingFactor, $maxHeight, $row[0], 1, 0, 'C');
|
||||
|
||||
// 2. Tanggal
|
||||
$this->Cell($columnWidths[1] * $scalingFactor, $maxHeight, $row[1], 1, 0, 'C');
|
||||
|
||||
// 3. Nama Item (multiline)
|
||||
$this->SetXY($x + ($columnWidths[0] + $columnWidths[1]) * $scalingFactor, $y);
|
||||
$this->MultiCell(
|
||||
$columnWidths[2] * $scalingFactor,
|
||||
$maxHeight / max(1, $nbDesc),
|
||||
$row[2],
|
||||
1,
|
||||
'L'
|
||||
);
|
||||
|
||||
// 4. Keterangan (multiline)
|
||||
$this->SetXY($x + ($columnWidths[0] + $columnWidths[1] + $columnWidths[2]) * $scalingFactor, $y);
|
||||
$this->MultiCell(
|
||||
$columnWidths[3] * $scalingFactor,
|
||||
$maxHeight / max(1, $nbKet),
|
||||
$row[3],
|
||||
1,
|
||||
'L'
|
||||
);
|
||||
|
||||
// 5. Qty
|
||||
$this->SetXY($x + ($columnWidths[0] + $columnWidths[1] + $columnWidths[2] + $columnWidths[3]) * $scalingFactor, $y);
|
||||
$this->Cell($columnWidths[4] * $scalingFactor, $maxHeight, $row[4], 1, 0, 'C');
|
||||
|
||||
// 6. Harga
|
||||
$this->Cell($columnWidths[5] * $scalingFactor, $maxHeight, $row[5], 1, 0, 'R');
|
||||
|
||||
// 7. Subtotal
|
||||
$this->Cell($columnWidths[6] * $scalingFactor, $maxHeight, $row[6], 1, 0, 'R');
|
||||
|
||||
$this->Ln($maxHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// Fungsi tambahan untuk menghitung jumlah baris Multicell
|
||||
function NbLines($w, $txt)
|
||||
{
|
||||
// Hitung jumlah baris dalam MultiCell
|
||||
$cw = &$this->CurrentFont['cw'];
|
||||
if ($w == 0) {
|
||||
$w = $this->w - $this->rMargin - $this->x;
|
||||
}
|
||||
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
|
||||
$s = str_replace("\r", '', $txt);
|
||||
$nb = strlen($s);
|
||||
if ($nb > 0 && $s[$nb - 1] == "\n") {
|
||||
$nb--;
|
||||
}
|
||||
$sep = -1;
|
||||
$i = 0;
|
||||
$j = 0;
|
||||
$l = 0;
|
||||
$nl = 1;
|
||||
while ($i < $nb) {
|
||||
$c = $s[$i];
|
||||
if ($c == "\n") {
|
||||
$i++;
|
||||
$sep = -1;
|
||||
$j = $i;
|
||||
$l = 0;
|
||||
$nl++;
|
||||
continue;
|
||||
}
|
||||
if ($c == ' ') {
|
||||
$sep = $i;
|
||||
}
|
||||
$l += $cw[$c];
|
||||
if ($l > $wmax) {
|
||||
if ($sep == -1) {
|
||||
if ($i == $j) {
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
$i = $sep + 1;
|
||||
}
|
||||
$sep = -1;
|
||||
$j = $i;
|
||||
$l = 0;
|
||||
$nl++;
|
||||
} else {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
return $nl;
|
||||
}
|
||||
|
||||
|
||||
function Total($subtotal,$lainnya,$totalAmount,$terbilang,$keteranganlain)
|
||||
{
|
||||
$this->Ln(1);
|
||||
$this->SetFont('Arial', '', 11);
|
||||
$this->Cell($this->maxWidth - 25, 9, 'Sub Total', 1, 0, 'R');
|
||||
$this->Cell(25, 9, $subtotal, 1, 1, 'R');
|
||||
$this->Cell($this->maxWidth - 25, 9, $keteranganlain, 1, 0, 'R');
|
||||
$this->Cell(25, 9, $lainnya, 1, 1, 'R');
|
||||
$this->SetFont('Arial', 'B', 11);
|
||||
$this->Cell($this->maxWidth - 25, 9, 'Total', 1, 0, 'R');
|
||||
$this->Cell(25, 9, $totalAmount, 1, 1, 'R');
|
||||
$this->Ln(1);
|
||||
$this->SetFont('Arial', 'I', 11);
|
||||
$this->Cell(0, 9, 'Terbilang : ', 0, 1);
|
||||
$this->SetFont('Arial', 'I', 11);
|
||||
$this->MultiCell(190, 9, $terbilang, 1, 'L');
|
||||
}
|
||||
|
||||
function Keterangan($Keterangan)
|
||||
{
|
||||
$this->Ln(10);
|
||||
$this->SetFont('Arial', '', 11);
|
||||
$this->SetFillColor(255, 140, 0);
|
||||
$this->MultiCell(100, 6, $Keterangan, 0, 'L', true);
|
||||
}
|
||||
|
||||
function Pembuat($Pembuat)
|
||||
{
|
||||
$this->Ln(-25);
|
||||
$this->SetFont('Arial', '', 11);
|
||||
$this->Cell(300, 6, 'Mengetahui,', 0, 1, 'C');
|
||||
$this->Ln(18);
|
||||
$this->SetFont('Arial', 'B', 11);
|
||||
$this->Cell(300, 6, '( '.$Pembuat.' )', 0, 1, 'C');
|
||||
$this->SetFont('Arial', 'I', 11);
|
||||
$this->Cell(300, 6, 'financial department', 0, 1, 'C');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,38 @@
|
||||
* 1.0.0 build 2010031920
|
||||
|
||||
- first public release
|
||||
- help in readme, install
|
||||
- cleanup ans separation of QRtools and QRspec
|
||||
- now TCPDF binding requires minimal changes in TCPDF, having most of job
|
||||
done in QRtools tcpdfBarcodeArray
|
||||
- nicer QRtools::timeBenchmark output
|
||||
- license and copyright notices in files
|
||||
- indent cleanup - from tab to 4spc, keep it that way please :)
|
||||
- sf project, repository, wiki
|
||||
- simple code generator in index.php
|
||||
|
||||
* 1.1.0 build 2010032113
|
||||
|
||||
- added merge tool wich generate merged version of code
|
||||
located in phpqrcode.php
|
||||
- splited qrconst.php from qrlib.php
|
||||
|
||||
* 1.1.1 build 2010032405
|
||||
|
||||
- patch by Rick Seymour allowing saving PNG and displaying it at the same time
|
||||
- added version info in VERSION file
|
||||
- modified merge tool to include version info into generated file
|
||||
- fixed e-mail in almost all head comments
|
||||
|
||||
* 1.1.2 build 2010032722
|
||||
|
||||
- full integration with TCPDF thanks to Nicola Asuni, it's author
|
||||
- fixed bug with alphanumeric encoding detection
|
||||
|
||||
* 1.1.3 build 2010081807
|
||||
|
||||
- short opening tags replaced with standard ones
|
||||
|
||||
* 1.1.4 build 2010100721
|
||||
|
||||
- added missing static keyword QRinput::check (found by Luke Brookhart, Onjax LLC)
|
||||
@@ -0,0 +1,67 @@
|
||||
== REQUIREMENTS ==
|
||||
|
||||
* PHP5
|
||||
* PHP GD2 extension with JPEG and PNG support
|
||||
|
||||
== INSTALLATION ==
|
||||
|
||||
If you want to recreate cache by yourself make sure cache directory is
|
||||
writable and you have permisions to write into it. Also make sure you are
|
||||
able to read files in it if you have cache option enabled
|
||||
|
||||
== CONFIGURATION ==
|
||||
|
||||
Feel free to modify config constants in qrconfig.php file. Read about it in
|
||||
provided comments and project wiki page (links in README file)
|
||||
|
||||
== QUICK START ==
|
||||
|
||||
Notice: probably you should'nt use all of this in same script :)
|
||||
|
||||
<?phpb
|
||||
|
||||
//include only that one, rest required files will be included from it
|
||||
include "qrlib.php"
|
||||
|
||||
//write code into file, Error corection lecer is lowest, L (one form: L,M,Q,H)
|
||||
//each code square will be 4x4 pixels (4x zoom)
|
||||
//code will have 2 code squares white boundary around
|
||||
|
||||
QRcode::png('PHP QR Code :)', 'test.png', 'L', 4, 2);
|
||||
|
||||
//same as above but outputs file directly into browser (with appr. header etc.)
|
||||
//all other settings are default
|
||||
//WARNING! it should be FIRST and ONLY output generated by script, otherwise
|
||||
//rest of output will land inside PNG binary, breaking it for sure
|
||||
QRcode::png('PHP QR Code :)');
|
||||
|
||||
//show benchmark
|
||||
QRtools::timeBenchmark();
|
||||
|
||||
//rebuild cache
|
||||
QRtools::buildCache();
|
||||
|
||||
//code generated in text mode - as a binary table
|
||||
//then displayed out as HTML using Unicode block building chars :)
|
||||
$tab = $qr->encode('PHP QR Code :)');
|
||||
QRspec::debug($tab, true);
|
||||
|
||||
== TCPDF INTEGRATION ==
|
||||
|
||||
Inside bindings/tcpdf you will find slightly modified 2dbarcodes.php.
|
||||
Instal phpqrcode liblaty inside tcpdf folder, then overwrite (or merge)
|
||||
2dbarcodes.php
|
||||
|
||||
Then use similar as example #50 from TCPDF examples:
|
||||
|
||||
<?php
|
||||
|
||||
$style = array(
|
||||
'border' => true,
|
||||
'padding' => 4,
|
||||
'fgcolor' => array(0,0,0),
|
||||
'bgcolor' => false, //array(255,255,255)
|
||||
);
|
||||
|
||||
//code name: QR, specify error correction level after semicolon (L,M,Q,H)
|
||||
$pdf->write2DBarcode('PHP QR Code :)', 'QR,L', '', '', 30, 30, $style, 'N');
|
||||
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -0,0 +1,45 @@
|
||||
This is PHP implementation of QR Code 2-D barcode generator. It is pure-php
|
||||
LGPL-licensed implementation based on C libqrencode by Kentaro Fukuchi.
|
||||
|
||||
== LICENSING ==
|
||||
|
||||
Copyright (C) 2010 by Dominik Dzienia
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License (LICENSE file)
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this library; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
== INSTALATION AND USAGE ==
|
||||
|
||||
* INSTALL file
|
||||
* http://sourceforge.net/apps/mediawiki/phpqrcode/index.php?title=Main_Page
|
||||
|
||||
== CONTACT ==
|
||||
|
||||
Fell free to contact me via e-mail (deltalab at poczta dot fm) or using
|
||||
folowing project pages:
|
||||
|
||||
* http://sourceforge.net/projects/phpqrcode/
|
||||
* http://phpqrcode.sourceforge.net/
|
||||
|
||||
== ACKNOWLEDGMENTS ==
|
||||
|
||||
Based on C libqrencode library (ver. 3.1.1)
|
||||
Copyright (C) 2006-2010 by Kentaro Fukuchi
|
||||
http://megaui.net/fukuchi/works/qrencode/index.en.html
|
||||
|
||||
QR Code is registered trademarks of DENSO WAVE INCORPORATED in JAPAN and other
|
||||
countries.
|
||||
|
||||
Reed-Solomon code encoder is written by Phil Karn, KA9Q.
|
||||
Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
1.1.4
|
||||
2010100721
|
||||
@@ -0,0 +1,2 @@
|
||||
xÚ��Á
À E9³u��`³"PÅ„CÛ牗T!0$
|
||||
E•ɲQ™�Ém½úhÛ¾9{kI"› 9Ln)Ap¤åÖ¾Ë>ß^‡Õz³mënÅ–;ü´mßn†ú¦Ë
|
||||
|
After Width: | Height: | Size: 126 B |
|
After Width: | Height: | Size: 202 B |
|
After Width: | Height: | Size: 205 B |
|
After Width: | Height: | Size: 216 B |
|
After Width: | Height: | Size: 210 B |
|
After Width: | Height: | Size: 213 B |
|
After Width: | Height: | Size: 219 B |
@@ -0,0 +1 @@
|
||||
xÚí™A„ E]sëIX´;¸Ün6€È`‚q”êêW6ñ奚`Œ%A/3!¢°‚¢Š!g–ÈÌ¡’1N)éE¢Ï|;®—>6â¸�Þ97$ëÄôëc]kkö�wé1Öü[·mCÍœcÊRºÄê¹>¦èµ¾šE,•hʼnp„#áxF�yWÏÇVWGçòÕ3¼Õ+шþàË“úSŽâ}Äž�#áG8b^c^cÏÀŽp„c&3YQ"ñŽ÷çÌvµù›…ñàÎþþ¼–¹kÞ9ŠÜ‡÷}”¹³ï×ú ¢Ä¿�QäÿL—/ÝÔÀÏ
|
||||
|
After Width: | Height: | Size: 211 B |
|
After Width: | Height: | Size: 211 B |
@@ -0,0 +1,2 @@
|
||||
xÚí™A
|
||||
ƒ0E]çÖ…,2;sƒä&ÉÍšh¥ÛêO¡ôÝÈàã1&09OIv@DDÒÌ&§Ù‰K�XÈÕFv•<Ádqò9Ö<%h•¹Yïs!(d¥²ës;~||b(ÏøYůg#µ`œK ±S¼Åô¹Ä¶˜ùsàidß�Lg:Ó™Îtþ/gmª�™ƒkÅMâ3³{4rTÈQýÿe¥·s·>ó<Ó™Ît¦3�éÌ;ïH¼#Ñ™Ît¦3�ÍYœ+og©hù¶óµÙ½¬lnðûF>Øi^»#awm;gè~pÛgìNs{6z’‘»ãºïÞäp¾Ê'
|
||||
|
After Width: | Height: | Size: 228 B |
@@ -0,0 +1,3 @@
|
||||
xÚíšA
|
||||
Ä E»öÖ.ĚNo 7Ń›Ť¶iiRÚN2‹áW%đxÁ@ÚÚśę'
|
||||
u�6×ę�.ť*S;}�«ŇĂ ĎTúčĚzrŤtąď%ç,ŇĹÚâÎ}ç;“âç)ąź�âÝZÚîLĺčą÷¬Pçç$Ż×÷ĎqËgśLÂôdJ‡;Üáw¸Ăý.]z#źľ«[Íť˝ďOg‚Ćô"ĐË áBíî¦}Ç}‡;Üáw¸Ăî�#1GbŽ„;Üáw¸Ăý_ÝC+w˘@Dfî÷ďç™uťř2™ĹÚÉNţű9R7|pWßkďű®ż“ßßkşöżşú»ĽÎÓ
|
||||
|
After Width: | Height: | Size: 225 B |
@@ -0,0 +1 @@
|
||||
xÚÍ’Í
À F{vë& à&°Y+?Z1öÐSŸ'y!¢ŸÌÁa�815&£•Û´ŽÙHå£Ùžc³•l«ÏFÆè1º#é6fÊÖü©§6Äø•O7ˆ¨†C¦«›ðÖ�ž�Ï8gI®ÏöfB¦ÃÄÿæ\DÔ»(
|
||||
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 225 B |
@@ -0,0 +1 @@
|
||||
xÚíšA„ E]sëIX´;¹Ün6Up‚�“в™ÿ]Ù˜þ<i-eWö‹¶˜)×äÅ•¼ÉÂ…H\jvqÙHL\6–šÝÐ…rI›¢LܹÜÕ%ÅÓ@´þ±V—vÆÂúý¤(ÏP4|ÎXnÒgÉ�ß¼~]D¾ÉÕ×u1Us S\À°€,ÿÅ2Þ¢N§Ã?D›KºüF-:“eJ]p_À°€,˜a0Ã`†ÁÝXÀ°`†Áƒw,`X´]˜ˆ™‚¹‹˜°5‰®Y4{屿ñ2íûåvçJs†±Ûí9±˜í)õu±Û¹êÏØ,«]¸“‹Ù^_§7$ƒ_Í
|
||||
|
After Width: | Height: | Size: 235 B |
@@ -0,0 +1,3 @@
|
||||
xÚíšA
|
||||
„0E]{ë�.’]{{{³©Z¥BepÆÞwe@�V›ERZ3»Á"*2o€4¦y‰)i#dÒbdFÒ…´ŒI"ú‘—4ž½WIíuŠÓ45ßx«.ZSÙ{ÁŸ¯8åËÿk={o.±qÊÙ£[œÍ:帒q»õƒy
|
||||
)t#á„N8ádCj�-O�OG}¼:/Ÿ:s�z!Å)^<ùe½·S·uâ{ 'œp 'ú=ú=ú=¾'œp 'œp¢ß£ß£ßã�N8á„Óÿ9©ªˆôpQQõ]HÔpz¾�ØGœ^æ½Qº˜I|¾ß³�u;9™ÎïÕëd;“X~$ËÙÑÉt¶ÊÛédy
|
||||