Merge branch 'Development' into master

This commit is contained in:
iBNu Maksum 2024-03-19 09:46:08 +07:00 committed by GitHub
commit 0dd12b717d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 364 additions and 216 deletions

View File

@ -26,6 +26,7 @@ CREATE TABLE `tbl_customers` (
`address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci, `address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0', `phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
`email` varchar(128) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1', `email` varchar(128) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1',
`coordinates` VARCHAR(50) NOT NULL DEFAULT '6.465422, 3.406448' COMMENT 'Latitude and Longitude coordinates',
`balance` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT 'For Money Deposit', `balance` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT 'For Money Deposit',
`service_type` ENUM('Hotspot','PPPoE','Others') DEFAULT 'Others' COMMENT 'For selecting user type', `service_type` ENUM('Hotspot','PPPoE','Others') DEFAULT 'Others' COMMENT 'For selecting user type',
`account_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type', `account_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type',

View File

@ -210,7 +210,7 @@ switch ($action) {
$customFields = ORM::for_table('tbl_customers_fields') $customFields = ORM::for_table('tbl_customers_fields')
->where('customer_id', $customer['id']) ->where('customer_id', $customer['id'])
->find_many(); ->find_many();
$v = $routes['3']; $v = $routes['3'];
if (empty ($v)) { if (empty ($v)) {
$v = 'activation'; $v = 'activation';
@ -330,6 +330,7 @@ switch ($action) {
$phonenumber = _post('phonenumber'); $phonenumber = _post('phonenumber');
$service_type = _post('service_type'); $service_type = _post('service_type');
$account_type = _post('account_type'); $account_type = _post('account_type');
$coordinates = _post('coordinates');
//post Customers Attributes //post Customers Attributes
$custom_field_names = (array) $_POST['custom_field_name']; $custom_field_names = (array) $_POST['custom_field_name'];
$custom_field_values = (array) $_POST['custom_field_value']; $custom_field_values = (array) $_POST['custom_field_value'];
@ -363,6 +364,7 @@ switch ($action) {
$d->created_by = $admin['id']; $d->created_by = $admin['id'];
$d->phonenumber = Lang::phoneFormat($phonenumber); $d->phonenumber = Lang::phoneFormat($phonenumber);
$d->service_type = $service_type; $d->service_type = $service_type;
$d->coordinates = $coordinates;
$d->save(); $d->save();
// Retrieve the customer ID of the newly created customer // Retrieve the customer ID of the newly created customer
@ -399,6 +401,7 @@ switch ($action) {
$address = _post('address'); $address = _post('address');
$phonenumber = Lang::phoneFormat(_post('phonenumber')); $phonenumber = Lang::phoneFormat(_post('phonenumber'));
$service_type = _post('service_type'); $service_type = _post('service_type');
$coordinates = _post('coordinates');
run_hook('edit_customer'); #HOOK run_hook('edit_customer'); #HOOK
$msg = ''; $msg = '';
if (Validator::Length($username, 35, 2) == false) { if (Validator::Length($username, 35, 2) == false) {
@ -459,6 +462,7 @@ switch ($action) {
$d->address = $address; $d->address = $address;
$d->phonenumber = $phonenumber; $d->phonenumber = $phonenumber;
$d->service_type = $service_type; $d->service_type = $service_type;
$d->coordinates = $coordinates;
$d->save(); $d->save();

View File

@ -0,0 +1,45 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
_admin();
$ui->assign('_system_menu', 'map');
$action = $routes['1'];
$ui->assign('_admin', $admin);
if (empty($action)) {
$action = 'customer';
}
switch ($action) {
case 'customer':
$c = ORM::for_table('tbl_customers')->find_many();
$customerData = [];
foreach ($c as $customer) {
$customerData[] = [
'id' => $customer->id,
'name' => $customer->fullname,
'balance' => $customer->balance,
'address' => $customer->address,
'info' => Lang::T("Username") . ": " . $customer->username . " - " . Lang::T("Full Name") . ": " . $customer->fullname . " - " . Lang::T("Email") . ": " . $customer->email . " - " . Lang::T("Phone") . ": " . $customer->phonenumber . " - " . Lang::T("Service Type") . ": " . $customer->service_type,
'coordinates' => '[' . $customer->coordinates . ']',
];
}
$ui->assign('customers', $customerData);
$ui->assign('xheader', '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">');
$ui->assign('_title', Lang::T('Customer Geo Location Information'));
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
$ui->display('map-customer.tpl');
break;
default:
r2(U . 'map/customer', 'e', 'action not defined');
break;
}

View File

@ -40,8 +40,11 @@ document.addEventListener("DOMContentLoaded", function(event) {
}); });
</script> </script>
EOT; EOT;
$c = ORM::for_table('tbl_customers')->find_many(); if (isset($routes['2']) && !empty($routes['2'])) {
$ui->assign('c', $c); $ui->assign('cust', ORM::for_table('tbl_customers')->find_one($routes['2']));
}
$id = $routes['2'];
$ui->assign('id', $id);
$ui->assign('xfooter', $select2_customer); $ui->assign('xfooter', $select2_customer);
$ui->display('message.tpl'); $ui->display('message.tpl');
break; break;

View File

@ -78,5 +78,10 @@
], ],
"2024.3.14" : [ "2024.3.14" : [
"ALTER TABLE `tbl_transactions` ADD `note` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'for note' AFTER `type`;" "ALTER TABLE `tbl_transactions` ADD `note` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'for note' AFTER `type`;"
],
"2024.3.19" : [
"ALTER TABLE `tbl_customers` ADD `coordinates` VARCHAR(50) NOT NULL DEFAULT '6.465422, 3.406448' COMMENT 'Latitude and Longitude coordinates' AFTER `email`;"
] ]
} }

View File

@ -11,10 +11,10 @@
<div class="col-md-9"> <div class="col-md-9">
<div class="input-group"> <div class="input-group">
{if $_c['country_code_phone']!= ''} {if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span> <span class="input-group-addon" id="basic-addon1">+</span>
{else} {else}
<span class="input-group-addon" id="basic-addon1"><i <span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span> class="glyphicon glyphicon-phone-alt"></i></span>
{/if} {/if}
<input type="text" class="form-control" name="username" required <input type="text" class="form-control" name="username" required
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}"> placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
@ -38,10 +38,10 @@
<div class="col-md-9"> <div class="col-md-9">
<div class="input-group"> <div class="input-group">
{if $_c['country_code_phone']!= ''} {if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span> <span class="input-group-addon" id="basic-addon1">+</span>
{else} {else}
<span class="input-group-addon" id="basic-addon1"><i <span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span> class="glyphicon glyphicon-phone-alt"></i></span>
{/if} {/if}
<input type="text" class="form-control" name="phonenumber" <input type="text" class="form-control" name="phonenumber"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}"> placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
@ -51,8 +51,9 @@
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Password')}</label> <label class="col-md-3 control-label">{Lang::T('Password')}</label>
<div class="col-md-9"> <div class="col-md-9">
<input type="password" class="form-control" autocomplete="off" required id="password" value="{rand(000000,999999)}" <input type="password" class="form-control" autocomplete="off" required id="password"
name="password" onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'"> value="{rand(000000,999999)}" name="password" onmouseleave="this.type = 'password'"
onmouseenter="this.type = 'text'">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -72,6 +73,17 @@
<textarea name="address" id="address" class="form-control"></textarea> <textarea name="address" id="address" class="form-control"></textarea>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Coordinates')}</label>
<div class="col-md-9">
<input name="coordinates" id="coordinates" class="form-control" value=""
placeholder="6.465422, 3.406448">
<span class="help-block">
<small>{Lang::T('Latitude and Longitude coordinates for map must be separate with comma
","')}</small>
</span>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Service Type')}</label> <label class="col-md-3 control-label">{Lang::T('Service Type')}</label>
<div class="col-md-9"> <div class="col-md-9">
@ -120,16 +132,16 @@
</center> </center>
</form> </form>
{literal} {literal}
<script type="text/javascript"> <script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function () {
var customFieldsContainer = document.getElementById('custom-fields-container'); var customFieldsContainer = document.getElementById('custom-fields-container');
var addCustomFieldButton = document.getElementById('add-custom-field'); var addCustomFieldButton = document.getElementById('add-custom-field');
addCustomFieldButton.addEventListener('click', function() { addCustomFieldButton.addEventListener('click', function () {
var fieldIndex = customFieldsContainer.children.length; var fieldIndex = customFieldsContainer.children.length;
var newField = document.createElement('div'); var newField = document.createElement('div');
newField.className = 'form-group'; newField.className = 'form-group';
newField.innerHTML = ` newField.innerHTML = `
<div class="col-md-4"> <div class="col-md-4">
<input type="text" class="form-control" name="custom_field_name[]" placeholder="Name"> <input type="text" class="form-control" name="custom_field_name[]" placeholder="Name">
</div> </div>
@ -140,17 +152,17 @@
<button type="button" class="remove-custom-field btn btn-danger btn-sm">-</button> <button type="button" class="remove-custom-field btn btn-danger btn-sm">-</button>
</div> </div>
`; `;
customFieldsContainer.appendChild(newField); customFieldsContainer.appendChild(newField);
});
customFieldsContainer.addEventListener('click', function(event) {
if (event.target.classList.contains('remove-custom-field')) {
var fieldContainer = event.target.parentNode.parentNode;
fieldContainer.parentNode.removeChild(fieldContainer);
}
});
}); });
</script>
customFieldsContainer.addEventListener('click', function (event) {
if (event.target.classList.contains('remove-custom-field')) {
var fieldContainer = event.target.parentNode.parentNode;
fieldContainer.parentNode.removeChild(fieldContainer);
}
});
});
</script>
{/literal} {/literal}

View File

@ -12,10 +12,10 @@
<div class="col-md-9"> <div class="col-md-9">
<div class="input-group"> <div class="input-group">
{if $_c['country_code_phone']!= ''} {if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span> <span class="input-group-addon" id="basic-addon1">+</span>
{else} {else}
<span class="input-group-addon" id="basic-addon1"><i <span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span> class="glyphicon glyphicon-phone-alt"></i></span>
{/if} {/if}
<input type="text" class="form-control" name="username" value="{$d['username']}" <input type="text" class="form-control" name="username" value="{$d['username']}"
required required
@ -41,10 +41,10 @@
<div class="col-md-9"> <div class="col-md-9">
<div class="input-group"> <div class="input-group">
{if $_c['country_code_phone']!= ''} {if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span> <span class="input-group-addon" id="basic-addon1">+</span>
{else} {else}
<span class="input-group-addon" id="basic-addon1"><i <span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span> class="glyphicon glyphicon-phone-alt"></i></span>
{/if} {/if}
<input type="text" class="form-control" name="phonenumber" value="{$d['phonenumber']}" <input type="text" class="form-control" name="phonenumber" value="{$d['phonenumber']}"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}"> placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
@ -77,6 +77,16 @@
<textarea name="address" id="address" class="form-control">{$d['address']}</textarea> <textarea name="address" id="address" class="form-control">{$d['address']}</textarea>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Coordinates')}</label>
<div class="col-md-9">
<input name="coordinates" id="coordinates" class="form-control" value="{$d['coordinates']}">
<span class="help-block">
<small>{Lang::T('Latitude and Longitude coordinates for map must be separate with comma
","')}</small>
</span>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Service Type')}</label> <label class="col-md-3 control-label">{Lang::T('Service Type')}</label>
<div class="col-md-9"> <div class="col-md-9">
@ -108,19 +118,20 @@
<div class="panel-body"> <div class="panel-body">
<!--Customers Attributes edit start --> <!--Customers Attributes edit start -->
{if $customFields} {if $customFields}
{foreach $customFields as $customField} {foreach $customFields as $customField}
<div class="form-group"> <div class="form-group">
<label class="col-md-4 control-label" <label class="col-md-4 control-label"
for="{$customField.field_name}">{$customField.field_name}</label> for="{$customField.field_name}">{$customField.field_name}</label>
<div class="col-md-6"> <div class="col-md-6">
<input class="form-control" type="text" name="custom_fields[{$customField.field_name}]" <input class="form-control" type="text" name="custom_fields[{$customField.field_name}]"
id="{$customField.field_name}" value="{$customField.field_value}"> id="{$customField.field_name}" value="{$customField.field_value}">
</div> </div>
<label class="col-md-2"> <label class="col-md-2">
<input type="checkbox" name="delete_custom_fields[]" value="{$customField.field_name}"> Delete <input type="checkbox" name="delete_custom_fields[]" value="{$customField.field_name}">
</label> Delete
</div> </label>
{/foreach} </div>
{/foreach}
{/if} {/if}
<!--Customers Attributes edit end --> <!--Customers Attributes edit end -->
<!-- Customers Attributes add start --> <!-- Customers Attributes add start -->
@ -144,16 +155,16 @@
</form> </form>
{literal} {literal}
<script type="text/javascript"> <script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function () {
var customFieldsContainer = document.getElementById('custom-fields-container'); var customFieldsContainer = document.getElementById('custom-fields-container');
var addCustomFieldButton = document.getElementById('add-custom-field'); var addCustomFieldButton = document.getElementById('add-custom-field');
addCustomFieldButton.addEventListener('click', function() { addCustomFieldButton.addEventListener('click', function () {
var fieldIndex = customFieldsContainer.children.length; var fieldIndex = customFieldsContainer.children.length;
var newField = document.createElement('div'); var newField = document.createElement('div');
newField.className = 'form-group'; newField.className = 'form-group';
newField.innerHTML = ` newField.innerHTML = `
<div class="col-md-4"> <div class="col-md-4">
<input type="text" class="form-control" name="custom_field_name[]" placeholder="Name"> <input type="text" class="form-control" name="custom_field_name[]" placeholder="Name">
</div> </div>
@ -164,17 +175,17 @@
<button type="button" class="remove-custom-field btn btn-danger btn-sm">-</button> <button type="button" class="remove-custom-field btn btn-danger btn-sm">-</button>
</div> </div>
`; `;
customFieldsContainer.appendChild(newField); customFieldsContainer.appendChild(newField);
});
customFieldsContainer.addEventListener('click', function(event) {
if (event.target.classList.contains('remove-custom-field')) {
var fieldContainer = event.target.parentNode.parentNode;
fieldContainer.parentNode.removeChild(fieldContainer);
}
});
}); });
</script>
customFieldsContainer.addEventListener('click', function (event) {
if (event.target.classList.contains('remove-custom-field')) {
var fieldContainer = event.target.parentNode.parentNode;
fieldContainer.parentNode.removeChild(fieldContainer);
}
});
});
</script>
{/literal} {/literal}
{include file="sections/footer.tpl"} {include file="sections/footer.tpl"}

View File

@ -30,26 +30,29 @@
onclick="this.select()"> onclick="this.select()">
</li> </li>
{if $d['pppoe_password'] != ''} {if $d['pppoe_password'] != ''}
<li class="list-group-item"> <li class="list-group-item">
<b>PPPOE {Lang::T('Password')}</b> <input type="password" value="{$d['pppoe_password']}" <b>PPPOE {Lang::T('Password')}</b> <input type="password" value="{$d['pppoe_password']}"
style=" border: 0px; text-align: right;" class="pull-right" style=" border: 0px; text-align: right;" class="pull-right"
onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'" onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'"
onclick="this.select()"> onclick="this.select()">
</li> </li>
{/if} {/if}
<li class="list-group-item">
<b>{Lang::T('Coordinates')}</b> <span class="pull-right">{Lang::T($d['coordinates'])}</span>
</li>
<!--Customers Attributes view start --> <!--Customers Attributes view start -->
{if $customFields} {if $customFields}
{foreach $customFields as $customField} {foreach $customFields as $customField}
<li class="list-group-item"> <li class="list-group-item">
<b>{$customField.field_name}</b> <span class="pull-right"> <b>{$customField.field_name}</b> <span class="pull-right">
{if strpos($customField.field_value, ':0') === false} {if strpos($customField.field_value, ':0') === false}
{$customField.field_value} {$customField.field_value}
{else} {else}
<b>{Lang::T('Paid')}</b> <b>{Lang::T('Paid')}</b>
{/if} {/if}
</span> </span>
</li> </li>
{/foreach} {/foreach}
{/if} {/if}
<!--Customers Attributes view end --> <!--Customers Attributes view end -->
<li class="list-group-item"> <li class="list-group-item">
@ -86,12 +89,12 @@
</div> </div>
</div> </div>
{foreach $packages as $package} {foreach $packages as $package}
<div class="box box-{if $package['status']=='on'}success{else}danger{/if}"> <div class="box box-{if $package['status']=='on'}success{else}danger{/if}">
<div class="box-body box-profile"> <div class="box-body box-profile">
<h4 class="text-center">{$package['type']} - {$package['namebp']}</h4> <h4 class="text-center">{$package['type']} - {$package['namebp']}</h4>
<ul class="list-group list-group-unbordered"> <ul class="list-group list-group-unbordered">
<li class="list-group-item"> <li class="list-group-item">
{Lang::T('Active')} <span class="pull-right">{if {Lang::T('Active')} <span class="pull-right">{if
$package['status']=='on'}yes{else}no $package['status']=='on'}yes{else}no
{/if}</span> {/if}</span>
</li> </li>
@ -104,7 +107,8 @@
class="pull-right">{Lang::dateAndTimeFormat($package['recharged_on'],$package['recharged_time'])}</span> class="pull-right">{Lang::dateAndTimeFormat($package['recharged_on'],$package['recharged_time'])}</span>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
{Lang::T('Expires On')} <span class="pull-right">{Lang::dateAndTimeFormat($package['expiration'], {Lang::T('Expires On')} <span
class="pull-right">{Lang::dateAndTimeFormat($package['expiration'],
$package['time'])}</span> $package['time'])}</span>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
@ -129,11 +133,15 @@
<div class="col-xs-4"> <div class="col-xs-4">
<a href="{$_url}customers/list" class="btn btn-primary btn-sm btn-block">{Lang::T('Back')}</a> <a href="{$_url}customers/list" class="btn btn-primary btn-sm btn-block">{Lang::T('Back')}</a>
</div> </div>
<div class="col-xs-8"> <div class="col-xs-4">
<a href="{$_url}customers/sync/{$d['id']}" <a href="{$_url}customers/sync/{$d['id']}"
onclick="return confirm('This will sync Customer to Mikrotik?')" onclick="return confirm('This will sync Customer to Mikrotik?')"
class="btn btn-info btn-sm btn-block">{Lang::T('Sync')}</a> class="btn btn-info btn-sm btn-block">{Lang::T('Sync')}</a>
</div> </div>
<div class="col-xs-4">
<a href="{$_url}message/send/{$d['id']}" class="btn btn-success btn-sm btn-block">{Lang::T('Send
Message')}</a>
</div>
</div> </div>
</div> </div>
<div class="col-sm-8 col-md-8"> <div class="col-sm-8 col-md-8">
@ -146,68 +154,68 @@
<div class="table-responsive" style="background-color: white;"> <div class="table-responsive" style="background-color: white;">
<table id="datatable" class="table table-bordered table-striped"> <table id="datatable" class="table table-bordered table-striped">
{if Lang::arrayCount($activation)} {if Lang::arrayCount($activation)}
<thead> <thead>
<tr> <tr>
<th>{Lang::T('Invoice')}</th> <th>{Lang::T('Invoice')}</th>
<th>{Lang::T('Username')}</th> <th>{Lang::T('Username')}</th>
<th>{Lang::T('Plan Name')}</th> <th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Plan Price')}</th> <th>{Lang::T('Plan Price')}</th>
<th>{Lang::T('Type')}</th> <th>{Lang::T('Type')}</th>
<th>{Lang::T('Created On')}</th> <th>{Lang::T('Created On')}</th>
<th>{Lang::T('Expires On')}</th> <th>{Lang::T('Expires On')}</th>
<th>{Lang::T('Method')}</th> <th>{Lang::T('Method')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{foreach $activation as $ds} {foreach $activation as $ds}
<tr onclick="window.location.href = '{$_url}plan/view/{$ds['id']}'" style="cursor:pointer;"> <tr onclick="window.location.href = '{$_url}plan/view/{$ds['id']}'" style="cursor:pointer;">
<td>{$ds['invoice']}</td> <td>{$ds['invoice']}</td>
<td>{$ds['username']}</td> <td>{$ds['username']}</td>
<td>{$ds['plan_name']}</td> <td>{$ds['plan_name']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td> <td>{Lang::moneyFormat($ds['price'])}</td>
<td>{$ds['type']}</td> <td>{$ds['type']}</td>
<td class="text-success">{Lang::dateAndTimeFormat($ds['recharged_on'],$ds['recharged_time'])} <td class="text-success">{Lang::dateAndTimeFormat($ds['recharged_on'],$ds['recharged_time'])}
</td> </td>
<td class="text-danger">{Lang::dateAndTimeFormat($ds['expiration'],$ds['time'])}</td> <td class="text-danger">{Lang::dateAndTimeFormat($ds['expiration'],$ds['time'])}</td>
<td>{$ds['method']}</td> <td>{$ds['method']}</td>
</tr> </tr>
{/foreach} {/foreach}
</tbody> </tbody>
{/if} {/if}
{if Lang::arrayCount($order)} {if Lang::arrayCount($order)}
<thead> <thead>
<tr> <tr>
<th>{Lang::T('Plan Name')}</th> <th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Gateway')}</th> <th>{Lang::T('Gateway')}</th>
<th>{Lang::T('Routers')}</th> <th>{Lang::T('Routers')}</th>
<th>{Lang::T('Type')}</th> <th>{Lang::T('Type')}</th>
<th>{Lang::T('Plan Price')}</th> <th>{Lang::T('Plan Price')}</th>
<th>{Lang::T('Created On')}</th> <th>{Lang::T('Created On')}</th>
<th>{Lang::T('Expires On')}</th> <th>{Lang::T('Expires On')}</th>
<th>{Lang::T('Date Done')}</th> <th>{Lang::T('Date Done')}</th>
<th>{Lang::T('Method')}</th> <th>{Lang::T('Method')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{foreach $order as $ds} {foreach $order as $ds}
<tr> <tr>
<td>{$ds['plan_name']}</td> <td>{$ds['plan_name']}</td>
<td>{$ds['gateway']}</td> <td>{$ds['gateway']}</td>
<td>{$ds['routers']}</td> <td>{$ds['routers']}</td>
<td>{$ds['payment_channel']}</td> <td>{$ds['payment_channel']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td> <td>{Lang::moneyFormat($ds['price'])}</td>
<td class="text-primary">{Lang::dateTimeFormat($ds['created_date'])}</td> <td class="text-primary">{Lang::dateTimeFormat($ds['created_date'])}</td>
<td class="text-danger">{Lang::dateTimeFormat($ds['expired_date'])}</td> <td class="text-danger">{Lang::dateTimeFormat($ds['expired_date'])}</td>
<td class="text-success">{if $ds['status']!=1}{Lang::dateTimeFormat($ds['paid_date'])}{/if}</td> <td class="text-success">{if $ds['status']!=1}{Lang::dateTimeFormat($ds['paid_date'])}{/if}</td>
<td>{if $ds['status']==1}{Lang::T('UNPAID')} <td>{if $ds['status']==1}{Lang::T('UNPAID')}
{elseif $ds['status']==2}{Lang::T('PAID')} {elseif $ds['status']==2}{Lang::T('PAID')}
{elseif $ds['status']==3}{$_L['FAILED']} {elseif $ds['status']==3}{$_L['FAILED']}
{elseif $ds['status']==4}{Lang::T('CANCELED')} {elseif $ds['status']==4}{Lang::T('CANCELED')}
{elseif $ds['status']==5}{Lang::T('UNKNOWN')} {elseif $ds['status']==5}{Lang::T('UNKNOWN')}
{/if}</td> {/if}</td>
</tr> </tr>
{/foreach} {/foreach}
</tbody> </tbody>
{/if} {/if}
</table> </table>
</div> </div>

46
ui/ui/map-customer.tpl Normal file
View File

@ -0,0 +1,46 @@
{include file="sections/header.tpl"}
<!-- Map container div -->
<div id="map" style="width: 800px; height: 600px; margin: 20px auto"></div>
{literal}
<script>
window.onload = function() {
var map = L.map('map').setView([51.505, -0.09], 13);
var group = L.featureGroup().addTo(map);
var customers = {/literal}{$customers|json_encode}{literal};
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
customers.forEach(function(customer) {
var name = customer.id;
var name = customer.name;
var info = customer.info;
var coordinates = customer.coordinates;
var balance = customer.balance;
var address = customer.address;
// Create a popup for the marker
var popupContent = "<strong>Customer Name</strong>: " + name + "<br>" +
"<strong>Customer Info</strong>: " + info + "<br>" +
"<strong>Customer Balance</strong>: " + balance + "<br>" +
"<strong>Address</strong>: " + address + "<br>" +
"<strong>Coordinates</strong>: " + coordinates + "<br>" +
"<a href='{$_url}customers/view/"+ customer.id +"'>More Info</a><br>";
// Add marker to map
var marker = L.marker(JSON.parse(coordinates)).addTo(group);
marker.bindTooltip(name).bindPopup(popupContent);
});
map.fitBounds(group.getBounds());
}
</script>
{/literal}
{include file="sections/footer.tpl"}

View File

@ -35,13 +35,13 @@
<p class="help-block col-md-4"> <p class="help-block col-md-4">
{Lang::T('Use placeholders:')} {Lang::T('Use placeholders:')}
<br> <br>
<b>{Lang::T('[[name]]')}</b> - {Lang::T('Customer Name')} <b>[[name]]</b> - {Lang::T('Customer Name')}
<br> <br>
<b>{Lang::T('[[user_name]]')}</b> - {Lang::T('Customer Username')} <b>[[user_name]]</b> - {Lang::T('Customer Username')}
<br> <br>
<b>{Lang::T('[[phone]]')}</b> - {Lang::T('Customer Phone')} <b>[[phone]]</b> - {Lang::T('Customer Phone')}
<br> <br>
<b>{Lang::T('[[company_name]]')}</b> - {Lang::T('Your Company Name')} <b>[[company_name]]</b> - {Lang::T('Your Company Name')}
</p> </p>
</div> </div>
@ -59,4 +59,4 @@
</div> </div>
{include file="sections/footer.tpl"} {include file="sections/footer.tpl"}

View File

@ -1,65 +1,64 @@
{include file="sections/header.tpl"} {include file="sections/header.tpl"}
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30"> <div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('Send Personal Message')}</div> <div class="panel-heading">{Lang::T('Send Personal Message')}</div>
<div class="panel-body"> <div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}message/send-post" > <form class="form-horizontal" method="post" role="form" action="{$_url}message/send-post">
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Customer')}</label> <label class="col-md-2 control-label">{Lang::T('Customer')}</label>
<div class="col-md-6"> <div class="col-md-6">
<select id="personSelect" class="form-control select2" name="id_customer" style="width: 100%" data-placeholder="Select a customer..."> <select {if $cust}{else}id="personSelect" {/if} class="form-control select2"
<option></option> name="id_customer" style="width: 100%"
{foreach $c as $cs} data-placeholder="{Lang::T('Select a customer')}...">
{if $id eq $cs['id']} {if $cust}
<option value="{$cs['id']}" selected>{$cs['username']}</option> <option value="{$cust['id']}">{$cust['username']} &bull; {$cust['fullname']} &bull;
{else} {$cust['email']}</option>
<option value="{$cs['id']}">{$cs['username']}</option> {/if}
{/if} </select>
{/foreach} </div>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Send Via')}</label>
<div class="col-md-6">
<select class="form-control" name="via" id="via">
<option value="sms" selected> {Lang::T('SMS')}</option>
<option value="wa"> {Lang::T('WhatsApp')}</option>
<option value="both"> {Lang::T('SMS and WhatsApp')}</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Message')}</label>
<div class="col-md-6">
<textarea class="form-control" id="message" name="message" placeholder="{Lang::T('Compose your message...')}" rows="5"></textarea>
</div>
<p class="help-block col-md-4">
{Lang::T('Use placeholders:')}
<br>
<b>{Lang::T('[[name]]')}</b> - {Lang::T('Customer Name')}
<br>
<b>{Lang::T('[[user_name]]')}</b> - {Lang::T('Customer Username')}
<br>
<b>{Lang::T('[[phone]]')}</b> - {Lang::T('Customer Phone')}
<br>
<b>{Lang::T('[[company_name]]')}</b> - {Lang::T('Your Company Name')}
</p>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-success" type="submit">{Lang::T('Send Message')}</button>
<a href="{$_url}dashboard" class="btn btn-default">{Lang::T('Cancel')}</a>
</div>
</div>
</form>
</div> </div>
</div> <div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Send Via')}</label>
<div class="col-md-6">
<select class="form-control" name="via" id="via">
<option value="sms" selected> {Lang::T('SMS')}</option>
<option value="wa"> {Lang::T('WhatsApp')}</option>
<option value="both"> {Lang::T('SMS and WhatsApp')}</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Message')}</label>
<div class="col-md-6">
<textarea class="form-control" id="message" name="message"
placeholder="{Lang::T('Compose your message...')}" rows="5"></textarea>
</div>
<p class="help-block col-md-4">
{Lang::T('Use placeholders:')}
<br>
<b>[[name]]</b> - {Lang::T('Customer Name')}
<br>
<b>[[user_name]]</b> - {Lang::T('Customer Username')}
<br>
<b>[[phone]]</b> - {Lang::T('Customer Phone')}
<br>
<b>[[company_name]]</b> - {Lang::T('Your Company Name')}
</p>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-success" type="submit">{Lang::T('Send Message')}</button>
<a href="{$_url}dashboard" class="btn btn-default">{Lang::T('Cancel')}</a>
</div>
</div>
</form>
</div> </div>
</div> </div>
</div>
</div>
{include file="sections/footer.tpl"} {include file="sections/footer.tpl"}

View File

@ -234,6 +234,20 @@
</ul> </ul>
</li> </li>
{$_MENU_AFTER_REPORTS} {$_MENU_AFTER_REPORTS}
<li class="{if $_system_menu eq 'map'}active{/if} treeview">
<a href="#">
<i class="ion ion-ios-location"></i> <span>{Lang::T('Map')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'customer' }class="active" {/if}><a
href="{$_url}map/customer">{Lang::T('Customer Location')}</a></li>
{$_MENU_MAP}
</ul>
</li>
{$_MENU_AFTER_MAP}
<li class="{if $_system_menu eq 'message'}active{/if} treeview"> <li class="{if $_system_menu eq 'message'}active{/if} treeview">
<a href="#"> <a href="#">
<i class="ion ion-android-chat"></i> <span>{Lang::T('Send Message')}</span> <i class="ion ion-android-chat"></i> <span>{Lang::T('Send Message')}</span>