Merge branch 'release-2.6.9'
Conflicts: app/Http/routes.php app/Ninja/PaymentDrivers/BasePaymentDriver.php composer.lock resources/lang/en/texts.php resources/views/reports/chart_builder.blade.php
@ -1,7 +1,7 @@
|
|||||||
APP_ENV=production
|
APP_ENV=production
|
||||||
APP_DEBUG=false
|
APP_DEBUG=false
|
||||||
APP_URL=http://ninja.dev
|
APP_URL=http://ninja.dev
|
||||||
APP_KEY=SomeRandomString
|
APP_KEY=SomeRandomStringSomeRandomString
|
||||||
APP_CIPHER=AES-256-CBC
|
APP_CIPHER=AES-256-CBC
|
||||||
|
|
||||||
DB_TYPE=mysql
|
DB_TYPE=mysql
|
||||||
|
5
.gitattributes
vendored
@ -1,3 +1,8 @@
|
|||||||
* text=auto
|
* text=auto
|
||||||
*.css linguist-vendored
|
*.css linguist-vendored
|
||||||
*.less linguist-vendored
|
*.less linguist-vendored
|
||||||
|
.gitattributes export-ignore
|
||||||
|
.gitignore export-ignore
|
||||||
|
.codeclimate.yml export-ignore
|
||||||
|
.travis.yml export-ignore
|
||||||
|
.styleci.yml export-ignore
|
||||||
|
@ -29,6 +29,7 @@ before_install:
|
|||||||
- if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi;
|
- if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi;
|
||||||
- composer self-update && composer -V
|
- composer self-update && composer -V
|
||||||
# - export USE_ZEND_ALLOC=0
|
# - export USE_ZEND_ALLOC=0
|
||||||
|
- rvm use 1.9.3 --install --fuzzy
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# install Composer dependencies
|
# install Composer dependencies
|
||||||
|
@ -2,8 +2,15 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Auto billing uses credits if they exist
|
||||||
|
|
||||||
|
|
||||||
|
## [2.6.4] - 2016-07-19
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Added 'Buy Now' buttons
|
- Added 'Buy Now' buttons
|
||||||
|
|
||||||
|
18
Gruntfile.js
@ -104,8 +104,8 @@ module.exports = function(grunt) {
|
|||||||
'public/vendor/moment-timezone/builds/moment-timezone-with-data.min.js',
|
'public/vendor/moment-timezone/builds/moment-timezone-with-data.min.js',
|
||||||
'public/vendor/stacktrace-js/dist/stacktrace-with-polyfills.min.js',
|
'public/vendor/stacktrace-js/dist/stacktrace-with-polyfills.min.js',
|
||||||
'public/vendor/fuse.js/src/fuse.min.js',
|
'public/vendor/fuse.js/src/fuse.min.js',
|
||||||
|
'public/vendor/sweetalert/dist/sweetalert.min.js',
|
||||||
//'public/vendor/moment-duration-format/lib/moment-duration-format.js',
|
//'public/vendor/moment-duration-format/lib/moment-duration-format.js',
|
||||||
//'public/vendor/handsontable/dist/jquery.handsontable.full.min.js',
|
|
||||||
//'public/vendor/pdfmake/build/pdfmake.min.js',
|
//'public/vendor/pdfmake/build/pdfmake.min.js',
|
||||||
//'public/vendor/pdfmake/build/vfs_fonts.js',
|
//'public/vendor/pdfmake/build/vfs_fonts.js',
|
||||||
//'public/js/vfs_fonts.js',
|
//'public/js/vfs_fonts.js',
|
||||||
@ -116,14 +116,12 @@ module.exports = function(grunt) {
|
|||||||
dest: 'public/built.js',
|
dest: 'public/built.js',
|
||||||
nonull: true
|
nonull: true
|
||||||
},
|
},
|
||||||
js_public: {
|
/*js_public: {
|
||||||
src: [
|
src: [
|
||||||
/*
|
|
||||||
'public/js/simpleexpand.js',
|
'public/js/simpleexpand.js',
|
||||||
'public/js/valign.js',
|
'public/js/valign.js',
|
||||||
'public/js/bootstrap.min.js',
|
'public/js/bootstrap.min.js',
|
||||||
'public/js/simpleexpand.js',
|
'public/js/simpleexpand.js',
|
||||||
*/
|
|
||||||
'public/vendor/bootstrap/dist/js/bootstrap.min.js',
|
'public/vendor/bootstrap/dist/js/bootstrap.min.js',
|
||||||
'public/js/bootstrap-combobox.js',
|
'public/js/bootstrap-combobox.js',
|
||||||
|
|
||||||
@ -142,7 +140,7 @@ module.exports = function(grunt) {
|
|||||||
'public/vendor/spectrum/spectrum.css',
|
'public/vendor/spectrum/spectrum.css',
|
||||||
'public/css/bootstrap-combobox.css',
|
'public/css/bootstrap-combobox.css',
|
||||||
'public/css/typeahead.js-bootstrap.css',
|
'public/css/typeahead.js-bootstrap.css',
|
||||||
//'public/vendor/handsontable/dist/jquery.handsontable.full.css',
|
'public/vendor/sweetalert/dist/sweetalert.css',
|
||||||
'public/css/style.css',
|
'public/css/style.css',
|
||||||
],
|
],
|
||||||
dest: 'public/css/built.css',
|
dest: 'public/css/built.css',
|
||||||
@ -150,8 +148,8 @@ module.exports = function(grunt) {
|
|||||||
options: {
|
options: {
|
||||||
process: false
|
process: false
|
||||||
}
|
}
|
||||||
},
|
},*/
|
||||||
css_public: {
|
/*css_public: {
|
||||||
src: [
|
src: [
|
||||||
'public/vendor/bootstrap/dist/css/bootstrap.min.css',
|
'public/vendor/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'public/vendor/font-awesome/css/font-awesome.min.css',
|
'public/vendor/font-awesome/css/font-awesome.min.css',
|
||||||
@ -165,8 +163,8 @@ module.exports = function(grunt) {
|
|||||||
options: {
|
options: {
|
||||||
process: false
|
process: false
|
||||||
}
|
}
|
||||||
},
|
},*/
|
||||||
js_pdf: {
|
/*js_pdf: {
|
||||||
src: [
|
src: [
|
||||||
'public/js/pdf_viewer.js',
|
'public/js/pdf_viewer.js',
|
||||||
'public/js/compatibility.js',
|
'public/js/compatibility.js',
|
||||||
@ -175,7 +173,7 @@ module.exports = function(grunt) {
|
|||||||
],
|
],
|
||||||
dest: 'public/pdf.built.js',
|
dest: 'public/pdf.built.js',
|
||||||
nonull: true
|
nonull: true
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
# Invoice Ninja
|
# Invoice Ninja
|
||||||
|
|
||||||
[](https://travis-ci.org/invoiceninja/invoiceninja)
|
[](https://travis-ci.org/invoiceninja/invoiceninja)
|
||||||
[](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
## [Hosted](https://www.invoiceninja.com) | [Self-hosted](https://invoiceninja.org)
|
## [Hosted](https://www.invoiceninja.com) | [Self-hosted](https://invoiceninja.org)
|
||||||
|
75
app/Console/Commands/ResetInvoiceSchemaCounter.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class ResetInvoiceSchemaCounter extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'ninja:reset-invoice-schema-counter
|
||||||
|
{account? : The ID of the account}
|
||||||
|
{--force : Force setting the counter back to "1", regardless if the year changed}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Reset the invoice schema counter at the turn of the year.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Invoice
|
||||||
|
*/
|
||||||
|
protected $invoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @param Invoice $invoice
|
||||||
|
*/
|
||||||
|
public function __construct(Invoice $invoice)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->invoice = $invoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$force = $this->option('force');
|
||||||
|
$account = $this->argument('account');
|
||||||
|
|
||||||
|
$accounts = null;
|
||||||
|
|
||||||
|
if ($account) {
|
||||||
|
$accounts = Account::find($account)->get();
|
||||||
|
} else {
|
||||||
|
$accounts = Account::all();
|
||||||
|
}
|
||||||
|
|
||||||
|
$latestInvoice = $this->invoice->latest()->first();
|
||||||
|
$invoiceYear = Carbon::parse($latestInvoice->created_at)->year;
|
||||||
|
|
||||||
|
if(Carbon::now()->year > $invoiceYear || $force) {
|
||||||
|
$accounts->transform(function ($a) {
|
||||||
|
/** @var Account $a */
|
||||||
|
$a->invoice_number_counter = 1;
|
||||||
|
$a->update();
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->info('The counter has been resetted successfully for '.$accounts->count().' account(s).');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,8 +21,8 @@ class Kernel extends ConsoleKernel
|
|||||||
'App\Console\Commands\SendRenewalInvoices',
|
'App\Console\Commands\SendRenewalInvoices',
|
||||||
'App\Console\Commands\ChargeRenewalInvoices',
|
'App\Console\Commands\ChargeRenewalInvoices',
|
||||||
'App\Console\Commands\SendReminders',
|
'App\Console\Commands\SendReminders',
|
||||||
'App\Console\Commands\TestOFX',
|
|
||||||
'App\Console\Commands\GenerateResources',
|
'App\Console\Commands\GenerateResources',
|
||||||
|
'App\Console\Commands\TestOFX',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1461,6 +1461,7 @@ class AccountController extends BaseController
|
|||||||
return trans('texts.create_invoice_for_sample');
|
return trans('texts.create_invoice_for_sample');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var \App\Models\Account $account */
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$invitation = $invoice->invitations->first();
|
$invitation = $invoice->invitations->first();
|
||||||
|
|
||||||
|
@ -60,6 +60,8 @@ class AccountGatewayController extends BaseController
|
|||||||
$data['hiddenFields'] = Gateway::$hiddenFields;
|
$data['hiddenFields'] = Gateway::$hiddenFields;
|
||||||
$data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get();
|
$data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get();
|
||||||
|
|
||||||
|
$this->testGateway($accountGateway);
|
||||||
|
|
||||||
return View::make('accounts.account_gateway', $data);
|
return View::make('accounts.account_gateway', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +309,7 @@ class AccountGatewayController extends BaseController
|
|||||||
$account->account_gateways()->save($accountGateway);
|
$account->account_gateways()->save($accountGateway);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($wepayResponse)) {
|
if (isset($wepayResponse)) {
|
||||||
return $wepayResponse;
|
return $wepayResponse;
|
||||||
} else {
|
} else {
|
||||||
if ($accountGatewayPublicId) {
|
if ($accountGatewayPublicId) {
|
||||||
@ -322,6 +324,16 @@ class AccountGatewayController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function testGateway($accountGateway)
|
||||||
|
{
|
||||||
|
$paymentDriver = $accountGateway->paymentDriver();
|
||||||
|
$result = $paymentDriver->isValid();
|
||||||
|
|
||||||
|
if ($result !== true) {
|
||||||
|
Session::flash('error', $result . ' - ' . trans('texts.gateway_config_error'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function getWePayUpdateUri($accountGateway)
|
protected function getWePayUpdateUri($accountGateway)
|
||||||
{
|
{
|
||||||
if ($accountGateway->gateway_id != GATEWAY_WEPAY) {
|
if ($accountGateway->gateway_id != GATEWAY_WEPAY) {
|
||||||
|
323
app/Http/Controllers/BotController.php
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use DB;
|
||||||
|
use Utils;
|
||||||
|
use Cache;
|
||||||
|
use Input;
|
||||||
|
use Exception;
|
||||||
|
use App\Libraries\Skype\SkypeResponse;
|
||||||
|
use App\Libraries\CurlUtils;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\SecurityCode;
|
||||||
|
use App\Ninja\Intents\BaseIntent;
|
||||||
|
use App\Ninja\Mailers\UserMailer;
|
||||||
|
|
||||||
|
class BotController extends Controller
|
||||||
|
{
|
||||||
|
protected $userMailer;
|
||||||
|
|
||||||
|
public function __construct(UserMailer $userMailer)
|
||||||
|
{
|
||||||
|
$this->userMailer = $userMailer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleMessage($platform)
|
||||||
|
{
|
||||||
|
$input = Input::all();
|
||||||
|
$botUserId = $input['from']['id'];
|
||||||
|
|
||||||
|
if ( ! $token = $this->authenticate($input)) {
|
||||||
|
return SkypeResponse::message(trans('texts.not_authorized'));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($input['type'] === 'contactRelationUpdate') {
|
||||||
|
// brand new user, ask for their email
|
||||||
|
if ($input['action'] === 'add') {
|
||||||
|
$response = SkypeResponse::message(trans('texts.bot_get_email'));
|
||||||
|
$state = BOT_STATE_GET_EMAIL;
|
||||||
|
} elseif ($input['action'] === 'remove') {
|
||||||
|
$this->removeBot($botUserId);
|
||||||
|
$this->saveState($token, false);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$state = $this->loadState($token);
|
||||||
|
$text = strip_tags($input['text']);
|
||||||
|
|
||||||
|
// user gaves us their email
|
||||||
|
if ($state === BOT_STATE_GET_EMAIL) {
|
||||||
|
if ($this->validateEmail($text, $botUserId)) {
|
||||||
|
$response = SkypeResponse::message(trans('texts.bot_get_code'));
|
||||||
|
$state = BOT_STATE_GET_CODE;
|
||||||
|
} else {
|
||||||
|
$response = SkypeResponse::message(trans('texts.email_not_found', ['email' => $text]));
|
||||||
|
}
|
||||||
|
// user sent the scurity code
|
||||||
|
} elseif ($state === BOT_STATE_GET_CODE) {
|
||||||
|
if ($this->validateCode($text, $botUserId)) {
|
||||||
|
$response = SkypeResponse::message(trans('texts.bot_welcome') . trans('texts.bot_help_message'));
|
||||||
|
$state = BOT_STATE_READY;
|
||||||
|
} else {
|
||||||
|
$response = SkypeResponse::message(trans('texts.invalid_code'));
|
||||||
|
}
|
||||||
|
// regular chat message
|
||||||
|
} else {
|
||||||
|
if ($message === 'help') {
|
||||||
|
$response = SkypeResponse::message(trans('texts.bot_help_message'));
|
||||||
|
} elseif ($message == 'status') {
|
||||||
|
$response = SkypeResponse::message(trans('texts.intent_not_supported'));
|
||||||
|
} else {
|
||||||
|
if ( ! $user = User::whereBotUserId($botUserId)->with('account')->first()) {
|
||||||
|
return SkypeResponse::message(trans('texts.not_authorized'));
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::onceUsingId($user->id);
|
||||||
|
$user->account->loadLocalizationSettings();
|
||||||
|
|
||||||
|
$data = $this->parseMessage($text);
|
||||||
|
$intent = BaseIntent::createIntent($state, $data);
|
||||||
|
$response = $intent->process();
|
||||||
|
$state = $intent->getState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->saveState($token, $state);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
$response = SkypeResponse::message($exception->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->sendResponse($token, $botUserId, $response);
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function authenticate($input)
|
||||||
|
{
|
||||||
|
$headers = getallheaders();
|
||||||
|
$token = isset($headers['Authorization']) ? $headers['Authorization'] : false;
|
||||||
|
|
||||||
|
if (Utils::isNinjaDev()) {
|
||||||
|
// skip validation for testing
|
||||||
|
} elseif ( ! $this->validateToken($token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($token = Cache::get('msbot_token')) {
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clientId = env('MSBOT_CLIENT_ID');
|
||||||
|
$clientSecret = env('MSBOT_CLIENT_SECRET');
|
||||||
|
$scope = 'https://graph.microsoft.com/.default';
|
||||||
|
|
||||||
|
$data = sprintf('grant_type=client_credentials&client_id=%s&client_secret=%s&scope=%s', $clientId, $clientSecret, $scope);
|
||||||
|
|
||||||
|
$response = CurlUtils::post(MSBOT_LOGIN_URL, $data);
|
||||||
|
$response = json_decode($response);
|
||||||
|
|
||||||
|
$expires = ($response->expires_in / 60) - 5;
|
||||||
|
Cache::put('msbot_token', $response->access_token, $expires);
|
||||||
|
|
||||||
|
return $response->access_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadState($token)
|
||||||
|
{
|
||||||
|
$url = sprintf('%s/botstate/skype/conversations/%s', MSBOT_STATE_URL, '29:1C-OsU7OWBEDOYJhQUsDkYHmycOwOq9QOg5FVTwRX9ts');
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Authorization: Bearer ' . $token
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = CurlUtils::get($url, $headers);
|
||||||
|
$data = json_decode($response);
|
||||||
|
|
||||||
|
return json_decode($data->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseMessage($message)
|
||||||
|
{
|
||||||
|
$appId = env('MSBOT_LUIS_APP_ID');
|
||||||
|
$subKey = env('MSBOT_LUIS_SUBSCRIPTION_KEY');
|
||||||
|
$message = rawurlencode($message);
|
||||||
|
|
||||||
|
$url = sprintf('%s?id=%s&subscription-key=%s&q=%s', MSBOT_LUIS_URL, $appId, $subKey, $message);
|
||||||
|
$data = file_get_contents($url);
|
||||||
|
$data = json_decode($data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveState($token, $data)
|
||||||
|
{
|
||||||
|
$url = sprintf('%s/botstate/skype/conversations/%s', MSBOT_STATE_URL, '29:1C-OsU7OWBEDOYJhQUsDkYHmycOwOq9QOg5FVTwRX9ts');
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Authorization: Bearer ' . $token,
|
||||||
|
'Content-Type: application/json',
|
||||||
|
];
|
||||||
|
|
||||||
|
//echo "STATE<pre>" . htmlentities(json_encode($data), JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
|
||||||
|
$data = '{ eTag: "*", data: "' . addslashes(json_encode($data)) . '" }';
|
||||||
|
|
||||||
|
|
||||||
|
CurlUtils::post($url, $data, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendResponse($token, $to, $message)
|
||||||
|
{
|
||||||
|
$url = sprintf('%s/conversations/%s/activities/', SKYPE_API_URL, $to);
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Authorization: Bearer ' . $token,
|
||||||
|
];
|
||||||
|
|
||||||
|
//echo "<pre>" . htmlentities(json_encode(json_decode($message), JSON_PRETTY_PRINT)) . "</pre>";
|
||||||
|
|
||||||
|
$response = CurlUtils::post($url, $message, $headers);
|
||||||
|
|
||||||
|
//var_dump($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateEmail($email, $botUserId)
|
||||||
|
{
|
||||||
|
if ( ! $email || ! $botUserId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete any expired codes
|
||||||
|
SecurityCode::whereBotUserId($botUserId)
|
||||||
|
->where('created_at', '<', DB::raw('now() - INTERVAL 10 MINUTE'))
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
if (SecurityCode::whereBotUserId($botUserId)->first()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::whereEmail($email)
|
||||||
|
->whereNull('bot_user_id')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ( ! $user) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = new SecurityCode();
|
||||||
|
$code->user_id = $user->id;
|
||||||
|
$code->account_id = $user->account_id;
|
||||||
|
$code->code = mt_rand(100000, 999999);
|
||||||
|
$code->bot_user_id = $botUserId;
|
||||||
|
$code->save();
|
||||||
|
|
||||||
|
$this->userMailer->sendSecurityCode($user, $code->code);
|
||||||
|
|
||||||
|
return $code->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateCode($input, $botUserId)
|
||||||
|
{
|
||||||
|
if ( ! $input || ! $botUserId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = SecurityCode::whereBotUserId($botUserId)
|
||||||
|
->where('created_at', '>', DB::raw('now() - INTERVAL 10 MINUTE'))
|
||||||
|
->where('attempts', '<', 5)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ( ! $code) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! hash_equals($code->code, $input)) {
|
||||||
|
$code->attempts += 1;
|
||||||
|
$code->save();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::find($code->user_id);
|
||||||
|
$user->bot_user_id = $code->bot_user_id;
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function removeBot($botUserId)
|
||||||
|
{
|
||||||
|
$user = User::whereBotUserId($botUserId)->first();
|
||||||
|
$user->bot_user_id = null;
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateToken($token)
|
||||||
|
{
|
||||||
|
if ( ! $token) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://blogs.msdn.microsoft.com/tsmatsuz/2016/07/12/developing-skype-bot/
|
||||||
|
// 0:Invalid, 1:Valid
|
||||||
|
$token_valid = 0;
|
||||||
|
|
||||||
|
// 1 separate token by dot (.)
|
||||||
|
$token_arr = explode('.', $token);
|
||||||
|
$headers_enc = $token_arr[0];
|
||||||
|
$claims_enc = $token_arr[1];
|
||||||
|
$sig_enc = $token_arr[2];
|
||||||
|
|
||||||
|
// 2 base 64 url decoding
|
||||||
|
$headers_arr = json_decode($this->base64_url_decode($headers_enc), TRUE);
|
||||||
|
$claims_arr = json_decode($this->base64_url_decode($claims_enc), TRUE);
|
||||||
|
$sig = $this->base64_url_decode($sig_enc);
|
||||||
|
|
||||||
|
// 3 get key list
|
||||||
|
$keylist = file_get_contents('https://api.aps.skype.com/v1/keys');
|
||||||
|
$keylist_arr = json_decode($keylist, TRUE);
|
||||||
|
foreach($keylist_arr['keys'] as $key => $value) {
|
||||||
|
|
||||||
|
// 4 select one key (which matches)
|
||||||
|
if($value['kid'] == $headers_arr['kid']) {
|
||||||
|
|
||||||
|
// 5 get public key from key info
|
||||||
|
$cert_txt = '-----BEGIN CERTIFICATE-----' . "\n" . chunk_split($value['x5c'][0], 64) . '-----END CERTIFICATE-----';
|
||||||
|
$cert_obj = openssl_x509_read($cert_txt);
|
||||||
|
$pkey_obj = openssl_pkey_get_public($cert_obj);
|
||||||
|
$pkey_arr = openssl_pkey_get_details($pkey_obj);
|
||||||
|
$pkey_txt = $pkey_arr['key'];
|
||||||
|
|
||||||
|
// 6 verify signature
|
||||||
|
$token_valid = openssl_verify($headers_enc . '.' . $claims_enc, $sig, $pkey_txt, OPENSSL_ALGO_SHA256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7 show result
|
||||||
|
return ($token_valid == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function base64_url_decode($arg) {
|
||||||
|
$res = $arg;
|
||||||
|
$res = str_replace('-', '+', $res);
|
||||||
|
$res = str_replace('_', '/', $res);
|
||||||
|
switch (strlen($res) % 4) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$res .= "==";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$res .= "=";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$res = base64_decode($res);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -52,7 +52,10 @@ class DocumentAPIController extends BaseAPIController
|
|||||||
{
|
{
|
||||||
$document = $request->entity();
|
$document = $request->entity();
|
||||||
|
|
||||||
return DocumentController::getDownloadResponse($document);
|
if(array_key_exists($document->type, Document::$types))
|
||||||
|
return DocumentController::getDownloadResponse($document);
|
||||||
|
else
|
||||||
|
return $this->errorResponse(['error'=>'Invalid mime type'],400);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -611,4 +611,15 @@ class InvoiceController extends BaseController
|
|||||||
|
|
||||||
return View::make('invoices.history', $data);
|
return View::make('invoices.history', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkInvoiceNumber($invoiceNumber)
|
||||||
|
{
|
||||||
|
$count = Invoice::scope()
|
||||||
|
->whereInvoiceNumber($invoiceNumber)
|
||||||
|
->withTrashed()
|
||||||
|
->count();
|
||||||
|
|
||||||
|
return $count ? RESULT_FAILURE : RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -130,8 +130,9 @@ class OnlinePaymentController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$paymentDriver->completeOffsitePurchase(Input::all());
|
if ($paymentDriver->completeOffsitePurchase(Input::all())) {
|
||||||
Session::flash('message', trans('texts.applied_payment'));
|
Session::flash('message', trans('texts.applied_payment'));
|
||||||
|
}
|
||||||
return redirect()->to('view/' . $invitation->invitation_key);
|
return redirect()->to('view/' . $invitation->invitation_key);
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
return $this->error($paymentDriver, $exception);
|
return $this->error($paymentDriver, $exception);
|
||||||
|
@ -25,6 +25,10 @@ class CreateInvoiceAPIRequest extends InvoiceRequest
|
|||||||
'invoice_items' => 'valid_invoice_items',
|
'invoice_items' => 'valid_invoice_items',
|
||||||
'invoice_number' => 'unique:invoices,invoice_number,,id,account_id,' . $this->user()->account_id,
|
'invoice_number' => 'unique:invoices,invoice_number,,id,account_id,' . $this->user()->account_id,
|
||||||
'discount' => 'positive',
|
'discount' => 'positive',
|
||||||
|
'invoice_date' => 'date',
|
||||||
|
'due_date' => 'date',
|
||||||
|
'start_date' => 'date',
|
||||||
|
'end_date' => 'date',
|
||||||
];
|
];
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
|
@ -24,6 +24,10 @@ class CreateInvoiceRequest extends InvoiceRequest
|
|||||||
'invoice_items' => 'valid_invoice_items',
|
'invoice_items' => 'valid_invoice_items',
|
||||||
'invoice_number' => 'required|unique:invoices,invoice_number,,id,account_id,' . $this->user()->account_id,
|
'invoice_number' => 'required|unique:invoices,invoice_number,,id,account_id,' . $this->user()->account_id,
|
||||||
'discount' => 'positive',
|
'discount' => 'positive',
|
||||||
|
'invoice_date' => 'date',
|
||||||
|
'due_date' => 'date',
|
||||||
|
'start_date' => 'date',
|
||||||
|
'end_date' => 'date',
|
||||||
];
|
];
|
||||||
|
|
||||||
/* There's a problem parsing the dates
|
/* There's a problem parsing the dates
|
||||||
|
@ -44,6 +44,11 @@ class EntityRequest extends Request {
|
|||||||
return $this->entity;
|
return $this->entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setEntity($entity)
|
||||||
|
{
|
||||||
|
$this->entity = $entity;
|
||||||
|
}
|
||||||
|
|
||||||
public function authorize()
|
public function authorize()
|
||||||
{
|
{
|
||||||
if ($this->entity()) {
|
if ($this->entity()) {
|
||||||
|
@ -29,6 +29,10 @@ class UpdateInvoiceAPIRequest extends InvoiceRequest
|
|||||||
'invoice_items' => 'valid_invoice_items',
|
'invoice_items' => 'valid_invoice_items',
|
||||||
'invoice_number' => 'unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
|
'invoice_number' => 'unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
|
||||||
'discount' => 'positive',
|
'discount' => 'positive',
|
||||||
|
'invoice_date' => 'date',
|
||||||
|
'due_date' => 'date',
|
||||||
|
'start_date' => 'date',
|
||||||
|
'end_date' => 'date',
|
||||||
];
|
];
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
|
@ -26,6 +26,10 @@ class UpdateInvoiceRequest extends InvoiceRequest
|
|||||||
'invoice_items' => 'valid_invoice_items',
|
'invoice_items' => 'valid_invoice_items',
|
||||||
'invoice_number' => 'required|unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
|
'invoice_number' => 'required|unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
|
||||||
'discount' => 'positive',
|
'discount' => 'positive',
|
||||||
|
'invoice_date' => 'date',
|
||||||
|
'due_date' => 'date',
|
||||||
|
'start_date' => 'date',
|
||||||
|
'end_date' => 'date',
|
||||||
];
|
];
|
||||||
|
|
||||||
/* There's a problem parsing the dates
|
/* There's a problem parsing the dates
|
||||||
|
37
app/Http/ViewComposers/AppLanguageComposer.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\ViewComposers;
|
||||||
|
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class AppLanguageComposer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bind data to the view.
|
||||||
|
*
|
||||||
|
* @param View $view
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function compose(View $view)
|
||||||
|
{
|
||||||
|
$view->with('appLanguage', $this->getLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language from the current locale
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getLanguage()
|
||||||
|
{
|
||||||
|
$code = app()->getLocale();
|
||||||
|
|
||||||
|
if(preg_match('/_/', $code)) {
|
||||||
|
$codes = explode('_', $code);
|
||||||
|
$code = $codes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
}
|
@ -85,6 +85,7 @@ Route::match(['GET', 'POST'], '/buy_now/{gateway_type?}', 'OnlinePaymentControll
|
|||||||
|
|
||||||
Route::post('/hook/email_bounced', 'AppController@emailBounced');
|
Route::post('/hook/email_bounced', 'AppController@emailBounced');
|
||||||
Route::post('/hook/email_opened', 'AppController@emailOpened');
|
Route::post('/hook/email_opened', 'AppController@emailOpened');
|
||||||
|
Route::post('/hook/bot/{platform?}', 'BotController@handleMessage');
|
||||||
Route::post('/payment_hook/{accountKey}/{gatewayId}', 'OnlinePaymentController@handlePaymentWebhook');
|
Route::post('/payment_hook/{accountKey}/{gatewayId}', 'OnlinePaymentController@handlePaymentWebhook');
|
||||||
|
|
||||||
// Laravel auth routes
|
// Laravel auth routes
|
||||||
@ -125,7 +126,8 @@ Route::group(['middleware' => 'auth:user'], function() {
|
|||||||
Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible');
|
Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible');
|
||||||
Route::get('hide_message', 'HomeController@hideMessage');
|
Route::get('hide_message', 'HomeController@hideMessage');
|
||||||
Route::get('force_inline_pdf', 'UserController@forcePDFJS');
|
Route::get('force_inline_pdf', 'UserController@forcePDFJS');
|
||||||
Route::get('account/getSearchData', ['as' => 'getSearchData', 'uses' => 'AccountController@getSearchData']);
|
Route::get('account/get_search_data', ['as' => 'get_search_data', 'uses' => 'AccountController@getSearchData']);
|
||||||
|
Route::get('check_invoice_number/{invoice_number}', 'InvoiceController@checkInvoiceNumber');
|
||||||
|
|
||||||
Route::get('settings/user_details', 'AccountController@showUserDetails');
|
Route::get('settings/user_details', 'AccountController@showUserDetails');
|
||||||
Route::post('settings/user_details', 'AccountController@saveUserDetails');
|
Route::post('settings/user_details', 'AccountController@saveUserDetails');
|
||||||
@ -351,7 +353,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('ENTITY_CONTACT', 'contact');
|
define('ENTITY_CONTACT', 'contact');
|
||||||
define('ENTITY_INVOICE', 'invoice');
|
define('ENTITY_INVOICE', 'invoice');
|
||||||
define('ENTITY_DOCUMENT', 'document');
|
define('ENTITY_DOCUMENT', 'document');
|
||||||
define('ENTITY_INVOICE_ITEMS', 'invoice_items');
|
define('ENTITY_INVOICE_ITEM', 'invoice_item');
|
||||||
define('ENTITY_INVITATION', 'invitation');
|
define('ENTITY_INVITATION', 'invitation');
|
||||||
define('ENTITY_RECURRING_INVOICE', 'recurring_invoice');
|
define('ENTITY_RECURRING_INVOICE', 'recurring_invoice');
|
||||||
define('ENTITY_PAYMENT', 'payment');
|
define('ENTITY_PAYMENT', 'payment');
|
||||||
@ -608,7 +610,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('NINJA_WEB_URL', env('NINJA_WEB_URL', 'https://www.invoiceninja.com'));
|
define('NINJA_WEB_URL', env('NINJA_WEB_URL', 'https://www.invoiceninja.com'));
|
||||||
define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com'));
|
define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com'));
|
||||||
define('NINJA_DATE', '2000-01-01');
|
define('NINJA_DATE', '2000-01-01');
|
||||||
define('NINJA_VERSION', '2.6.8' . env('NINJA_VERSION_SUFFIX'));
|
define('NINJA_VERSION', '2.6.9' . env('NINJA_VERSION_SUFFIX'));
|
||||||
|
|
||||||
define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja'));
|
define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja'));
|
||||||
define('SOCIAL_LINK_TWITTER', env('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja'));
|
define('SOCIAL_LINK_TWITTER', env('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja'));
|
||||||
@ -626,6 +628,11 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('OFX_HOME_URL', env('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all'));
|
define('OFX_HOME_URL', env('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all'));
|
||||||
define('GOOGLE_ANALYITCS_URL', env('GOOGLE_ANALYITCS_URL', 'https://www.google-analytics.com/collect'));
|
define('GOOGLE_ANALYITCS_URL', env('GOOGLE_ANALYITCS_URL', 'https://www.google-analytics.com/collect'));
|
||||||
|
|
||||||
|
define('MSBOT_LOGIN_URL', 'https://login.microsoftonline.com/common/oauth2/v2.0/token');
|
||||||
|
define('MSBOT_LUIS_URL', 'https://api.projectoxford.ai/luis/v1/application');
|
||||||
|
define('SKYPE_API_URL', 'https://apis.skype.com/v3');
|
||||||
|
define('MSBOT_STATE_URL', 'https://state.botframework.com/v3');
|
||||||
|
|
||||||
define('BLANK_IMAGE', 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=');
|
define('BLANK_IMAGE', 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=');
|
||||||
|
|
||||||
define('COUNT_FREE_DESIGNS', 4);
|
define('COUNT_FREE_DESIGNS', 4);
|
||||||
@ -790,6 +797,25 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('WEPAY_APP_FEE_MULTIPLIER', env('WEPAY_APP_FEE_MULTIPLIER', 0.002));
|
define('WEPAY_APP_FEE_MULTIPLIER', env('WEPAY_APP_FEE_MULTIPLIER', 0.002));
|
||||||
define('WEPAY_APP_FEE_FIXED', env('WEPAY_APP_FEE_MULTIPLIER', 0.00));
|
define('WEPAY_APP_FEE_FIXED', env('WEPAY_APP_FEE_MULTIPLIER', 0.00));
|
||||||
|
|
||||||
|
define('SKYPE_CARD_RECEIPT', 'message/card.receipt');
|
||||||
|
define('SKYPE_CARD_CAROUSEL', 'message/card.carousel');
|
||||||
|
define('SKYPE_CARD_HERO', '');
|
||||||
|
|
||||||
|
define('BOT_STATE_GET_EMAIL', 'get_email');
|
||||||
|
define('BOT_STATE_GET_CODE', 'get_code');
|
||||||
|
define('BOT_STATE_READY', 'ready');
|
||||||
|
define('SIMILAR_MIN_THRESHOLD', 50);
|
||||||
|
|
||||||
|
// https://docs.botframework.com/en-us/csharp/builder/sdkreference/attachments.html
|
||||||
|
define('SKYPE_BUTTON_OPEN_URL', 'openUrl');
|
||||||
|
define('SKYPE_BUTTON_IM_BACK', 'imBack');
|
||||||
|
define('SKYPE_BUTTON_POST_BACK', 'postBack');
|
||||||
|
define('SKYPE_BUTTON_CALL', 'call'); // "tel:123123123123"
|
||||||
|
define('SKYPE_BUTTON_PLAY_AUDIO', 'playAudio');
|
||||||
|
define('SKYPE_BUTTON_PLAY_VIDEO', 'playVideo');
|
||||||
|
define('SKYPE_BUTTON_SHOW_IMAGE', 'showImage');
|
||||||
|
define('SKYPE_BUTTON_DOWNLOAD_FILE', 'downloadFile');
|
||||||
|
|
||||||
$creditCards = [
|
$creditCards = [
|
||||||
1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
|
1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
|
||||||
2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
|
2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
|
||||||
|
36
app/Libraries/CurlUtils.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php namespace App\Libraries;
|
||||||
|
|
||||||
|
class CurlUtils
|
||||||
|
{
|
||||||
|
public static function post($url, $data, $headers = false)
|
||||||
|
{
|
||||||
|
return self::exec('POST', $url, $data, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get($url, $headers = false)
|
||||||
|
{
|
||||||
|
return self::exec('GET', $url, null, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function exec($method, $url, $data, $headers = false)
|
||||||
|
{
|
||||||
|
$curl = curl_init();
|
||||||
|
|
||||||
|
$opts = [
|
||||||
|
CURLOPT_URL => $url,
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_POST => $method,
|
||||||
|
CURLOPT_HTTPHEADER => $headers ?: [],
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($data) {
|
||||||
|
$opts[CURLOPT_POSTFIELDS] = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_setopt_array($curl, $opts);
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
12
app/Libraries/Skype/ButtonCard.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php namespace App\Libraries\Skype;
|
||||||
|
|
||||||
|
class ButtonCard
|
||||||
|
{
|
||||||
|
public function __construct($type, $title, $value, $url = false)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
$this->title = $title;
|
||||||
|
$this->value = $value;
|
||||||
|
$this->image = $url;
|
||||||
|
}
|
||||||
|
}
|
15
app/Libraries/Skype/CarouselCard.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php namespace App\Libraries\Skype;
|
||||||
|
|
||||||
|
class CarouselCard
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->contentType = 'application/vnd.microsoft.card.carousel';
|
||||||
|
$this->attachments = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addAttachment($attachment)
|
||||||
|
{
|
||||||
|
$this->attachments[] = $attachment;
|
||||||
|
}
|
||||||
|
}
|
33
app/Libraries/Skype/HeroCard.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php namespace App\Libraries\Skype;
|
||||||
|
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
class HeroCard
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->contentType = 'application/vnd.microsoft.card.hero';
|
||||||
|
$this->content = new stdClass;
|
||||||
|
$this->content->buttons = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTitle($title)
|
||||||
|
{
|
||||||
|
$this->content->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSubitle($subtitle)
|
||||||
|
{
|
||||||
|
$this->content->subtitle = $subtitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setText($text)
|
||||||
|
{
|
||||||
|
$this->content->text = $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addButton($type, $title, $value, $url = false)
|
||||||
|
{
|
||||||
|
$this->content->buttons[] = new ButtonCard($type, $title, $value, $url);
|
||||||
|
}
|
||||||
|
}
|
79
app/Libraries/Skype/InvoiceCard.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php namespace App\Libraries\Skype;
|
||||||
|
|
||||||
|
use HTML;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
class InvoiceCard
|
||||||
|
{
|
||||||
|
public function __construct($invoice)
|
||||||
|
{
|
||||||
|
$this->contentType = 'application/vnd.microsoft.card.receipt';
|
||||||
|
$this->content = new stdClass;
|
||||||
|
$this->content->facts = [];
|
||||||
|
$this->content->items = [];
|
||||||
|
$this->content->buttons = [];
|
||||||
|
|
||||||
|
$this->setTitle('test');
|
||||||
|
|
||||||
|
$this->setTitle(trans('texts.invoice_for_client', [
|
||||||
|
'invoice' => link_to($invoice->getRoute(), $invoice->invoice_number),
|
||||||
|
'client' => link_to($invoice->client->getRoute(), $invoice->client->getDisplayName())
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->addFact(trans('texts.email'), HTML::mailto($invoice->client->contacts[0]->email)->toHtml());
|
||||||
|
|
||||||
|
if ($invoice->due_date) {
|
||||||
|
$this->addFact($invoice->present()->dueDateLabel, $invoice->present()->due_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($invoice->po_number) {
|
||||||
|
$this->addFact(trans('texts.po_number'), $invoice->po_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($invoice->discount) {
|
||||||
|
$this->addFact(trans('texts.discount'), $invoice->present()->discount);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($invoice->invoice_items as $item) {
|
||||||
|
$this->addItem($item, $invoice->account);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setTotal($invoice->present()->requestedAmount);
|
||||||
|
|
||||||
|
if (floatval($invoice->amount)) {
|
||||||
|
$this->addButton(SKYPE_BUTTON_OPEN_URL, trans('texts.download_pdf'), $invoice->getInvitationLink('view', true));
|
||||||
|
$this->addButton(SKYPE_BUTTON_IM_BACK, trans('texts.email_invoice'), trans('texts.email_invoice'));
|
||||||
|
} else {
|
||||||
|
$this->addButton(SKYPE_BUTTON_IM_BACK, trans('texts.list_products'), trans('texts.list_products'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTitle($title)
|
||||||
|
{
|
||||||
|
$this->content->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTotal($value)
|
||||||
|
{
|
||||||
|
$this->content->total = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addFact($key, $value)
|
||||||
|
{
|
||||||
|
$fact = new stdClass;
|
||||||
|
$fact->key = $key;
|
||||||
|
$fact->value = $value;
|
||||||
|
|
||||||
|
$this->content->facts[] = $fact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addItem($item, $account)
|
||||||
|
{
|
||||||
|
$this->content->items[] = new InvoiceItemCard($item, $account);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addButton($type, $title, $value, $url = false)
|
||||||
|
{
|
||||||
|
$this->content->buttons[] = new ButtonCard($type, $title, $value, $url);
|
||||||
|
}
|
||||||
|
}
|
12
app/Libraries/Skype/InvoiceItemCard.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php namespace App\Libraries\Skype;
|
||||||
|
|
||||||
|
class InvoiceItemCard
|
||||||
|
{
|
||||||
|
public function __construct($invoiceItem, $account)
|
||||||
|
{
|
||||||
|
$this->title = intval($invoiceItem->qty) . ' ' . $invoiceItem->product_key;
|
||||||
|
$this->subtitle = $invoiceItem->notes;
|
||||||
|
$this->quantity = $invoiceItem->qty;
|
||||||
|
$this->price = $account->formatMoney($invoiceItem->cost);
|
||||||
|
}
|
||||||
|
}
|
28
app/Libraries/Skype/SkypeResponse.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php namespace App\Libraries\Skype;
|
||||||
|
|
||||||
|
class SkypeResponse
|
||||||
|
{
|
||||||
|
public function __construct($type)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
$this->attachments = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function message($message)
|
||||||
|
{
|
||||||
|
$instance = new self('message/text');
|
||||||
|
$instance->setText($message);
|
||||||
|
|
||||||
|
return json_encode($instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setText($text)
|
||||||
|
{
|
||||||
|
$this->text = $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addAttachment($attachment)
|
||||||
|
{
|
||||||
|
$this->attachments[] = $attachment;
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
use Auth;
|
use Auth;
|
||||||
use Eloquent;
|
use Eloquent;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
use Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class EntityModel
|
* Class EntityModel
|
||||||
@ -86,6 +87,11 @@ class EntityModel extends Eloquent
|
|||||||
return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getDisplayName() . ']';
|
return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getDisplayName() . ']';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function entityKey()
|
||||||
|
{
|
||||||
|
return $this->public_id . ':' . $this->getEntityType();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public function getEntityType()
|
public function getEntityType()
|
||||||
{
|
{
|
||||||
@ -190,4 +196,37 @@ class EntityModel extends Eloquent
|
|||||||
$name = $parts[count($parts)-1];
|
$name = $parts[count($parts)-1];
|
||||||
return strtolower($name) . '_id';
|
return strtolower($name) . '_id';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
* @param $entityType
|
||||||
|
* @return bool|string
|
||||||
|
*/
|
||||||
|
public static function validate($data, $entityType, $entity = false)
|
||||||
|
{
|
||||||
|
// Use the API request if it exists
|
||||||
|
$action = $entity ? 'update' : 'create';
|
||||||
|
$requestClass = sprintf('App\\Http\\Requests\\%s%sAPIRequest', ucwords($action), ucwords($entityType));
|
||||||
|
if ( ! class_exists($requestClass)) {
|
||||||
|
$requestClass = sprintf('App\\Http\\Requests\\%s%sRequest', ucwords($action), ucwords($entityType));
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = new $requestClass();
|
||||||
|
$request->setUserResolver(function() { return Auth::user(); });
|
||||||
|
$request->setEntity($entity);
|
||||||
|
$request->replace($data);
|
||||||
|
|
||||||
|
if ( ! $request->authorize()) {
|
||||||
|
return trans('texts.not_allowed');
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator = Validator::make($data, $request->rules());
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return $validator->messages()->first();
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -516,6 +516,15 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
return self::calcLink($this);
|
return self::calcLink($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getInvitationLink($type = 'view', $forceOnsite = false)
|
||||||
|
{
|
||||||
|
if ( ! $this->relationLoaded('invitations')) {
|
||||||
|
$this->load('invitations');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->invitations[0]->getLink($type, $forceOnsite);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,14 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||||||
*/
|
*/
|
||||||
class InvoiceItem extends EntityModel
|
class InvoiceItem extends EntityModel
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getEntityType()
|
||||||
|
{
|
||||||
|
return ENTITY_INVOICE_ITEM;
|
||||||
|
}
|
||||||
|
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php namespace App\Models;
|
<?php namespace App\Models;
|
||||||
|
|
||||||
|
use Laracasts\Presenter\PresentableTrait;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -7,12 +8,18 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||||||
*/
|
*/
|
||||||
class Product extends EntityModel
|
class Product extends EntityModel
|
||||||
{
|
{
|
||||||
|
use PresentableTrait;
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $dates = ['deleted_at'];
|
protected $dates = ['deleted_at'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $presenter = 'App\Ninja\Presenters\ProductPresenter';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
|
15
app/Models/SecurityCode.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php namespace App\Models;
|
||||||
|
|
||||||
|
use Eloquent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class DatetimeFormat
|
||||||
|
*/
|
||||||
|
class SecurityCode extends Eloquent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
}
|
227
app/Ninja/Intents/BaseIntent.php
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
<?php namespace App\Ninja\Intents;
|
||||||
|
|
||||||
|
use stdClass;
|
||||||
|
use Exception;
|
||||||
|
use App\Libraries\CurlUtils;
|
||||||
|
use App\Libraries\Skype\SkypeResponse;
|
||||||
|
|
||||||
|
class BaseIntent
|
||||||
|
{
|
||||||
|
protected $state;
|
||||||
|
protected $parameters;
|
||||||
|
protected $fieldMap = [];
|
||||||
|
|
||||||
|
public function __construct($state, $data)
|
||||||
|
{
|
||||||
|
//if (true) {
|
||||||
|
if ( ! $state || is_string($state)) {
|
||||||
|
$state = new stdClass;
|
||||||
|
foreach (['current', 'previous'] as $reference) {
|
||||||
|
$state->$reference = new stdClass;
|
||||||
|
$state->$reference->entityType = false;
|
||||||
|
foreach ([ENTITY_INVOICE, ENTITY_CLIENT, ENTITY_INVOICE_ITEM] as $entityType) {
|
||||||
|
$state->$reference->$entityType = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->state = $state;
|
||||||
|
$this->data = $data;
|
||||||
|
|
||||||
|
//var_dump($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createIntent($state, $data)
|
||||||
|
{
|
||||||
|
if ( ! count($data->intents)) {
|
||||||
|
throw new Exception(trans('texts.intent_not_found'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$intent = $data->intents[0]->intent;
|
||||||
|
$entityType = false;
|
||||||
|
|
||||||
|
foreach ($data->entities as $entity) {
|
||||||
|
if ($entity->type === 'EntityType') {
|
||||||
|
$entityType = $entity->entity;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $entityType) {
|
||||||
|
$entityType = $state->current->entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entityType = ucwords(strtolower($entityType));
|
||||||
|
$intent = str_replace('Entity', $entityType, $intent);
|
||||||
|
$className = "App\\Ninja\\Intents\\{$intent}Intent";
|
||||||
|
|
||||||
|
//echo "Intent: $intent<p>";
|
||||||
|
|
||||||
|
if ( ! class_exists($className)) {
|
||||||
|
throw new Exception(trans('texts.intent_not_supported'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (new $className($state, $data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function process()
|
||||||
|
{
|
||||||
|
// do nothing by default
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStateEntities($entityType, $entities)
|
||||||
|
{
|
||||||
|
if ( ! is_array($entities)) {
|
||||||
|
$entities = [$entities];
|
||||||
|
}
|
||||||
|
|
||||||
|
$state = $this->state;
|
||||||
|
|
||||||
|
$state->previous->$entityType = $state->current->$entityType;
|
||||||
|
$state->current->$entityType = $entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStateEntityType($entityType)
|
||||||
|
{
|
||||||
|
$state = $this->state;
|
||||||
|
|
||||||
|
if ($state->current->entityType == $entityType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$state->previous->entityType = $state->current->entityType;
|
||||||
|
$state->current->entityType = $entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stateEntities($entityType)
|
||||||
|
{
|
||||||
|
return $this->state->current->$entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stateEntity($entityType)
|
||||||
|
{
|
||||||
|
$entities = $this->state->current->$entityType;
|
||||||
|
|
||||||
|
return count($entities) ? $entities[0] : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function previousStateEntities($entityType)
|
||||||
|
{
|
||||||
|
return $this->state->previous->$entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stateEntityType()
|
||||||
|
{
|
||||||
|
return $this->state->current->entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getState()
|
||||||
|
{
|
||||||
|
return $this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function requestClient()
|
||||||
|
{
|
||||||
|
$clientRepo = app('App\Ninja\Repositories\ClientRepository');
|
||||||
|
$client = false;
|
||||||
|
|
||||||
|
foreach ($this->data->entities as $param) {
|
||||||
|
if ($param->type == 'Name') {
|
||||||
|
$client = $clientRepo->findPhonetically($param->entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $client;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function requestFields()
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
if ( ! isset($this->data->compositeEntities)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->data->compositeEntities as $compositeEntity) {
|
||||||
|
if ($compositeEntity->parentType != 'FieldValuePair') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$field = false;
|
||||||
|
$value = false;
|
||||||
|
|
||||||
|
foreach ($compositeEntity->children as $child) {
|
||||||
|
if ($child->type == 'Field') {
|
||||||
|
$field = $child->value;;
|
||||||
|
} elseif ($child->type == 'Value') {
|
||||||
|
$value = $child->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($field && $value) {
|
||||||
|
$field = $this->processField($field);
|
||||||
|
$value = $this->processValue($value);
|
||||||
|
|
||||||
|
$data[$field] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->fieldMap as $key => $value) {
|
||||||
|
if (isset($data[$key])) {
|
||||||
|
$data[$value] = $data[$key];
|
||||||
|
unset($data[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processField($field)
|
||||||
|
{
|
||||||
|
$field = str_replace(' ', '_', $field);
|
||||||
|
|
||||||
|
if (strpos($field, 'date') !== false) {
|
||||||
|
$field .= '_sql';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $field;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processValue($value)
|
||||||
|
{
|
||||||
|
// look for LUIS pre-built entity matches
|
||||||
|
foreach ($this->data->entities as $entity) {
|
||||||
|
if ($entity->entity === $value) {
|
||||||
|
if ($entity->type == 'builtin.datetime.date') {
|
||||||
|
$value = $entity->resolution->date;
|
||||||
|
$value = str_replace('XXXX', date('Y'), $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createResponse($type, $content)
|
||||||
|
{
|
||||||
|
$response = new SkypeResponse($type);
|
||||||
|
|
||||||
|
if (is_string($content)) {
|
||||||
|
$response->setText($content);
|
||||||
|
} else {
|
||||||
|
if ($content instanceof \Illuminate\Database\Eloquent\Collection) {
|
||||||
|
// do nothing
|
||||||
|
} elseif ( ! is_array($content)) {
|
||||||
|
$content = [$content];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($content as $item) {
|
||||||
|
$response->addAttachment($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_encode($response);
|
||||||
|
}
|
||||||
|
}
|
44
app/Ninja/Intents/CreateInvoiceIntent.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php namespace App\Ninja\Intents;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use App\Models\EntityModel;
|
||||||
|
|
||||||
|
class CreateInvoiceIntent extends InvoiceIntent
|
||||||
|
{
|
||||||
|
public function process()
|
||||||
|
{
|
||||||
|
$client = $this->requestClient();
|
||||||
|
$invoiceItems = $this->requestInvoiceItems();
|
||||||
|
|
||||||
|
if ( ! $client) {
|
||||||
|
throw new Exception(trans('texts.client_not_found'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = array_merge($this->requestFields(), [
|
||||||
|
'client_id' => $client->id,
|
||||||
|
'invoice_items' => $invoiceItems,
|
||||||
|
]);
|
||||||
|
|
||||||
|
//var_dump($data);
|
||||||
|
|
||||||
|
$valid = EntityModel::validate($data, ENTITY_INVOICE);
|
||||||
|
|
||||||
|
if ($valid !== true) {
|
||||||
|
throw new Exception($valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoiceService = app('App\Services\InvoiceService');
|
||||||
|
$invoice = $invoiceService->save($data);
|
||||||
|
|
||||||
|
$invoiceItemIds = array_map(function($item) {
|
||||||
|
return $item['public_id'];
|
||||||
|
}, $invoice->invoice_items->toArray());
|
||||||
|
|
||||||
|
$this->setStateEntityType(ENTITY_INVOICE);
|
||||||
|
$this->setStateEntities(ENTITY_CLIENT, $client->public_id);
|
||||||
|
$this->setStateEntities(ENTITY_INVOICE, $invoice->public_id);
|
||||||
|
$this->setStateEntities(ENTITY_INVOICE_ITEM, $invoiceItemIds);
|
||||||
|
|
||||||
|
return $this->createResponse(SKYPE_CARD_RECEIPT, $invoice->present()->skypeBot);
|
||||||
|
}
|
||||||
|
}
|
19
app/Ninja/Intents/DownloadInvoiceIntent.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php namespace App\Ninja\Intents;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use App\Models\EntityModel;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Libraries\Skype\SkypeResponse;
|
||||||
|
|
||||||
|
class DownloadInvoiceIntent extends InvoiceIntent
|
||||||
|
{
|
||||||
|
public function process()
|
||||||
|
{
|
||||||
|
$invoice = $this->invoice();
|
||||||
|
|
||||||
|
$message = trans('texts.' . $invoice->getEntityType()) . ' ' . $invoice->invoice_number;
|
||||||
|
$message = link_to('/download/' . $invoice->invitations[0]->invitation_key, $message);
|
||||||
|
|
||||||
|
return SkypeResponse::message($message);
|
||||||
|
}
|
||||||
|
}
|
32
app/Ninja/Intents/EmailInvoiceIntent.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php namespace App\Ninja\Intents;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Exception;
|
||||||
|
use App\Models\EntityModel;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Libraries\Skype\SkypeResponse;
|
||||||
|
|
||||||
|
class EmailInvoiceIntent extends InvoiceIntent
|
||||||
|
{
|
||||||
|
public function process()
|
||||||
|
{
|
||||||
|
$invoice = $this->stateInvoice();
|
||||||
|
|
||||||
|
if ( ! Auth::user()->can('edit', $invoice)) {
|
||||||
|
throw new Exception(trans('texts.not_allowed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$contactMailer = app('App\Ninja\Mailers\ContactMailer');
|
||||||
|
$contactMailer->sendInvoice($invoice);
|
||||||
|
|
||||||
|
$message = trans('texts.bot_emailed_' . $invoice->getEntityType());
|
||||||
|
|
||||||
|
if (Auth::user()->notify_viewed) {
|
||||||
|
$message .= '<br/>' . trans('texts.bot_emailed_notify_viewed');
|
||||||
|
} elseif (Auth::user()->notify_paid) {
|
||||||
|
$message .= '<br/>' . trans('texts.bot_emailed_notify_paid');
|
||||||
|
}
|
||||||
|
|
||||||
|
return SkypeResponse::message($message);
|
||||||
|
}
|
||||||
|
}
|
93
app/Ninja/Intents/InvoiceIntent.php
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<?php namespace App\Ninja\Intents;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Exception;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
|
||||||
|
class InvoiceIntent extends BaseIntent
|
||||||
|
{
|
||||||
|
protected $fieldMap = [
|
||||||
|
'deposit' => 'partial',
|
||||||
|
'due' => 'due_date',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct($state, $data)
|
||||||
|
{
|
||||||
|
$this->invoiceRepo = app('App\Ninja\Repositories\InvoiceRepository');
|
||||||
|
|
||||||
|
parent::__construct($state, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function stateInvoice()
|
||||||
|
{
|
||||||
|
$invoiceId = $this->stateEntity(ENTITY_INVOICE);
|
||||||
|
|
||||||
|
if ( ! $invoiceId) {
|
||||||
|
throw new Exception(trans('texts.intent_not_supported'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice = Invoice::scope($invoiceId)->first();
|
||||||
|
|
||||||
|
if ( ! $invoice) {
|
||||||
|
throw new Exception(trans('texts.intent_not_supported'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! Auth::user()->can('view', $invoice)) {
|
||||||
|
throw new Exception(trans('texts.not_allowed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $invoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function requestInvoiceItems()
|
||||||
|
{
|
||||||
|
$productRepo = app('App\Ninja\Repositories\ProductRepository');
|
||||||
|
|
||||||
|
$invoiceItems = [];
|
||||||
|
|
||||||
|
if ( ! isset($this->data->compositeEntities) || ! count($this->data->compositeEntities)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->data->compositeEntities as $entity) {
|
||||||
|
if ($entity->parentType == 'InvoiceItem') {
|
||||||
|
$product = false;
|
||||||
|
$qty = 1;
|
||||||
|
foreach ($entity->children as $child) {
|
||||||
|
if ($child->type == 'Product') {
|
||||||
|
$product = $productRepo->findPhonetically($child->value);
|
||||||
|
} else {
|
||||||
|
$qty = $child->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($product) {
|
||||||
|
$item['qty'] = $qty;
|
||||||
|
$item['product_key'] = $product->product_key;
|
||||||
|
$item['cost'] = $product->cost;
|
||||||
|
$item['notes'] = $product->notes;
|
||||||
|
|
||||||
|
if ($taxRate = $product->default_tax_rate) {
|
||||||
|
$item['tax_name1'] = $taxRate->name;
|
||||||
|
$item['tax_rate1'] = $taxRate->rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoiceItems[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if ( ! count($invoiceItems)) {
|
||||||
|
foreach ($this->data->entities as $param) {
|
||||||
|
if ($param->type == 'Product') {
|
||||||
|
$product = $productRepo->findPhonetically($param->entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return $invoiceItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
app/Ninja/Intents/ListProductsIntent.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php namespace App\Ninja\Intents;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Exception;
|
||||||
|
use App\Models\Product;
|
||||||
|
|
||||||
|
|
||||||
|
class ListProductsIntent extends ProductIntent
|
||||||
|
{
|
||||||
|
public function process()
|
||||||
|
{
|
||||||
|
$account = Auth::user()->account;
|
||||||
|
$products = Product::scope()
|
||||||
|
->orderBy('product_key')
|
||||||
|
->limit(10)
|
||||||
|
->get()
|
||||||
|
->transform(function($item, $key) use ($account) {
|
||||||
|
$card = $item->present()->skypeBot($account);
|
||||||
|
if ($this->stateEntity(ENTITY_INVOICE)) {
|
||||||
|
$card->addButton('imBack', trans('texts.add_to_invoice'), trans('texts.add_product_to_invoice', ['product' => $item->product_key]));
|
||||||
|
}
|
||||||
|
return $card;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->createResponse(SKYPE_CARD_CAROUSEL, $products);
|
||||||
|
}
|
||||||
|
}
|
15
app/Ninja/Intents/ProductIntent.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php namespace App\Ninja\Intents;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class ProductIntent extends BaseIntent
|
||||||
|
{
|
||||||
|
public function __construct($state, $data)
|
||||||
|
{
|
||||||
|
$this->productRepo = app('App\Ninja\Repositories\ProductRepository');
|
||||||
|
|
||||||
|
parent::__construct($state, $data);
|
||||||
|
}
|
||||||
|
}
|
54
app/Ninja/Intents/UpdateInvoiceIntent.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php namespace App\Ninja\Intents;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use App\Models\EntityModel;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
|
||||||
|
class UpdateInvoiceIntent extends InvoiceIntent
|
||||||
|
{
|
||||||
|
public function process()
|
||||||
|
{
|
||||||
|
$invoice = $this->stateInvoice();
|
||||||
|
$invoiceItems = $this->requestInvoiceItems();
|
||||||
|
|
||||||
|
$data = array_merge($this->requestFields(), [
|
||||||
|
'public_id' => $invoice->public_id,
|
||||||
|
'invoice_items' => array_merge($invoice->invoice_items->toArray(), $invoiceItems),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// map the cost and qty fields to the invoice items
|
||||||
|
if (isset($data['cost']) || isset($data['quantity'])) {
|
||||||
|
foreach ($data['invoice_items'] as $key => $item) {
|
||||||
|
// if it's new or we recently created it
|
||||||
|
if (empty($item['public_id']) || in_array($item['public_id'], $this->entities(ENTITY_INVOICE_ITEM))) {
|
||||||
|
$data['invoice_items'][$key]['cost'] = isset($data['cost']) ? $data['cost'] : $item['cost'];
|
||||||
|
$data['invoice_items'][$key]['qty'] = isset($data['quantity']) ? $data['quantity'] : $item['qty'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//var_dump($data);
|
||||||
|
|
||||||
|
$valid = EntityModel::validate($data, ENTITY_INVOICE, $invoice);
|
||||||
|
|
||||||
|
if ($valid !== true) {
|
||||||
|
throw new Exception($valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice = $this->invoiceRepo->save($data, $invoice);
|
||||||
|
|
||||||
|
$invoiceItems = array_slice($invoice->invoice_items->toArray(), count($invoiceItems) * -1);
|
||||||
|
$invoiceItemIds = array_map(function($item) {
|
||||||
|
return $item['public_id'];
|
||||||
|
}, $invoiceItems);
|
||||||
|
|
||||||
|
$this->setStateEntities(ENTITY_INVOICE_ITEM, $invoiceItemIds);
|
||||||
|
|
||||||
|
$response = $invoice
|
||||||
|
->load('invoice_items')
|
||||||
|
->present()
|
||||||
|
->skypeBot;
|
||||||
|
|
||||||
|
return $this->createResponse(SKYPE_CARD_RECEIPT, $response);
|
||||||
|
}
|
||||||
|
}
|
@ -109,4 +109,20 @@ class UserMailer extends Mailer
|
|||||||
|
|
||||||
$this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
$this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function sendSecurityCode($user, $code)
|
||||||
|
{
|
||||||
|
if (!$user->email) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$subject = trans('texts.security_code_email_subject');
|
||||||
|
$view = 'security_code';
|
||||||
|
$data = [
|
||||||
|
'userName' => $user->getDisplayName(),
|
||||||
|
'code' => $code,
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,11 @@ class BasePaymentDriver
|
|||||||
return $this->accountGateway->gateway_id == $gatewayId;
|
return $this->accountGateway->gateway_id == $gatewayId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isValid()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// optionally pass a paymentMethod to determine the type from the token
|
// optionally pass a paymentMethod to determine the type from the token
|
||||||
protected function isGatewayType($gatewayType, $paymentMethod = false)
|
protected function isGatewayType($gatewayType, $paymentMethod = false)
|
||||||
{
|
{
|
||||||
@ -535,6 +540,15 @@ class BasePaymentDriver
|
|||||||
$paymentMethod->setRelation('account_gateway_token', $customer);
|
$paymentMethod->setRelation('account_gateway_token', $customer);
|
||||||
$paymentMethod = $this->creatingPaymentMethod($paymentMethod);
|
$paymentMethod = $this->creatingPaymentMethod($paymentMethod);
|
||||||
|
|
||||||
|
// archive the old payment method
|
||||||
|
$oldPaymentMethod = PaymentMethod::clientId($this->client()->id)
|
||||||
|
->wherePaymentTypeId($paymentMethod->payment_type_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($oldPaymentMethod) {
|
||||||
|
$oldPaymentMethod->delete();
|
||||||
|
}
|
||||||
|
|
||||||
if ($paymentMethod) {
|
if ($paymentMethod) {
|
||||||
$paymentMethod->save();
|
$paymentMethod->save();
|
||||||
}
|
}
|
||||||
@ -753,7 +767,7 @@ class BasePaymentDriver
|
|||||||
} elseif ($paymentMethod->payment_type_id == PAYMENT_TYPE_PAYPAL) {
|
} elseif ($paymentMethod->payment_type_id == PAYMENT_TYPE_PAYPAL) {
|
||||||
$label = 'PayPal: ' . $paymentMethod->email;
|
$label = 'PayPal: ' . $paymentMethod->email;
|
||||||
} else {
|
} else {
|
||||||
$label = trans('texts.use_card_on_file');
|
$label = trans('texts.payment_type_on_file', ['type' => $paymentMethod->payment_type->name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$links[] = [
|
$links[] = [
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?php namespace App\Ninja\PaymentDrivers;
|
<?php namespace App\Ninja\PaymentDrivers;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
class MolliePaymentDriver extends BasePaymentDriver
|
class MolliePaymentDriver extends BasePaymentDriver
|
||||||
{
|
{
|
||||||
public function completeOffsitePurchase($input)
|
public function completeOffsitePurchase($input)
|
||||||
@ -10,6 +12,12 @@ class MolliePaymentDriver extends BasePaymentDriver
|
|||||||
|
|
||||||
$response = $this->gateway()->fetchTransaction($details)->send();
|
$response = $this->gateway()->fetchTransaction($details)->send();
|
||||||
|
|
||||||
|
if ($response->isCancelled()) {
|
||||||
|
return false;
|
||||||
|
} elseif ( ! $response->isSuccessful()) {
|
||||||
|
throw new Exception($response->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
return $this->createPayment($response->getTransactionReference());
|
return $this->createPayment($response->getTransactionReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,21 @@ class StripePaymentDriver extends BasePaymentDriver
|
|||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isValid()
|
||||||
|
{
|
||||||
|
$result = $this->makeStripeCall(
|
||||||
|
'GET',
|
||||||
|
'charges',
|
||||||
|
'limit=1'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (array_get($result, 'object') == 'list') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function checkCustomerExists($customer)
|
protected function checkCustomerExists($customer)
|
||||||
{
|
{
|
||||||
$response = $this->gateway()
|
$response = $this->gateway()
|
||||||
@ -347,15 +362,15 @@ class StripePaymentDriver extends BasePaymentDriver
|
|||||||
$eventDetails = $this->makeStripeCall('GET', 'events/'.$eventId);
|
$eventDetails = $this->makeStripeCall('GET', 'events/'.$eventId);
|
||||||
|
|
||||||
if (is_string($eventDetails) || !$eventDetails) {
|
if (is_string($eventDetails) || !$eventDetails) {
|
||||||
throw new Exception('Could not get event details');
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($eventType != $eventDetails['type']) {
|
if ($eventType != $eventDetails['type']) {
|
||||||
throw new Exception('Event type mismatch');
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$eventDetails['pending_webhooks']) {
|
if (!$eventDetails['pending_webhooks']) {
|
||||||
throw new Exception('This is not a pending event');
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($eventType == 'charge.failed' || $eventType == 'charge.succeeded' || $eventType == 'charge.refunded') {
|
if ($eventType == 'charge.failed' || $eventType == 'charge.succeeded' || $eventType == 'charge.refunded') {
|
||||||
@ -365,7 +380,7 @@ class StripePaymentDriver extends BasePaymentDriver
|
|||||||
$payment = Payment::scope(false, $accountId)->where('transaction_reference', '=', $transactionRef)->first();
|
$payment = Payment::scope(false, $accountId)->where('transaction_reference', '=', $transactionRef)->first();
|
||||||
|
|
||||||
if (!$payment) {
|
if (!$payment) {
|
||||||
throw new Exception('Unknown payment');
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($eventType == 'charge.failed') {
|
if ($eventType == 'charge.failed') {
|
||||||
|
@ -8,6 +8,22 @@ class ClientPresenter extends EntityPresenter {
|
|||||||
return $this->entity->country ? $this->entity->country->name : '';
|
return $this->entity->country ? $this->entity->country->name : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function balance()
|
||||||
|
{
|
||||||
|
$client = $this->entity;
|
||||||
|
$account = $client->account;
|
||||||
|
|
||||||
|
return $account->formatMoney($client->balance, $client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function paid_to_date()
|
||||||
|
{
|
||||||
|
$client = $this->entity;
|
||||||
|
$account = $client->account;
|
||||||
|
|
||||||
|
return $account->formatMoney($client->paid_to_date, $client);
|
||||||
|
}
|
||||||
|
|
||||||
public function status()
|
public function status()
|
||||||
{
|
{
|
||||||
$class = $text = '';
|
$class = $text = '';
|
||||||
|
@ -5,7 +5,6 @@ use Laracasts\Presenter\Presenter;
|
|||||||
|
|
||||||
class EntityPresenter extends Presenter
|
class EntityPresenter extends Presenter
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php namespace App\Ninja\Presenters;
|
<?php namespace App\Ninja\Presenters;
|
||||||
|
|
||||||
use Utils;
|
use Utils;
|
||||||
|
use App\Libraries\Skype\InvoiceCard;
|
||||||
|
|
||||||
class InvoicePresenter extends EntityPresenter {
|
class InvoicePresenter extends EntityPresenter {
|
||||||
|
|
||||||
@ -14,6 +15,22 @@ class InvoicePresenter extends EntityPresenter {
|
|||||||
return $this->entity->user->getDisplayName();
|
return $this->entity->user->getDisplayName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function amount()
|
||||||
|
{
|
||||||
|
$invoice = $this->entity;
|
||||||
|
$account = $invoice->account;
|
||||||
|
|
||||||
|
return $account->formatMoney($invoice->amount, $invoice->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requestedAmount()
|
||||||
|
{
|
||||||
|
$invoice = $this->entity;
|
||||||
|
$account = $invoice->account;
|
||||||
|
|
||||||
|
return $account->formatMoney($invoice->getRequestedAmount(), $invoice->client);
|
||||||
|
}
|
||||||
|
|
||||||
public function balanceDueLabel()
|
public function balanceDueLabel()
|
||||||
{
|
{
|
||||||
if ($this->entity->partial > 0) {
|
if ($this->entity->partial > 0) {
|
||||||
@ -25,6 +42,26 @@ class InvoicePresenter extends EntityPresenter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function dueDateLabel()
|
||||||
|
{
|
||||||
|
if ($this->entity->isType(INVOICE_TYPE_STANDARD)) {
|
||||||
|
return trans('texts.due_date');
|
||||||
|
} else {
|
||||||
|
return trans('texts.valid_until');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function discount()
|
||||||
|
{
|
||||||
|
$invoice = $this->entity;
|
||||||
|
|
||||||
|
if ($invoice->is_amount_discount) {
|
||||||
|
return $invoice->account->formatMoney($invoice->discount);
|
||||||
|
} else {
|
||||||
|
return $invoice->discount . '%';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://schema.org/PaymentStatusType
|
// https://schema.org/PaymentStatusType
|
||||||
public function paymentStatus()
|
public function paymentStatus()
|
||||||
{
|
{
|
||||||
@ -99,4 +136,9 @@ class InvoicePresenter extends EntityPresenter {
|
|||||||
|
|
||||||
return trans('texts.auto_bill_notification', $data);
|
return trans('texts.auto_bill_notification', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function skypeBot()
|
||||||
|
{
|
||||||
|
return new InvoiceCard($this->entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
20
app/Ninja/Presenters/ProductPresenter.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php namespace App\Ninja\Presenters;
|
||||||
|
|
||||||
|
use App\Libraries\Skype\HeroCard;
|
||||||
|
|
||||||
|
class ProductPresenter extends EntityPresenter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function skypeBot($account)
|
||||||
|
{
|
||||||
|
$product = $this->entity;
|
||||||
|
|
||||||
|
$card = new HeroCard();
|
||||||
|
$card->setTitle($product->product_key);
|
||||||
|
$card->setSubitle($account->formatMoney($product->cost));
|
||||||
|
$card->setText($product->notes);
|
||||||
|
|
||||||
|
return $card;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -132,4 +132,47 @@ class ClientRepository extends BaseRepository
|
|||||||
|
|
||||||
return $client;
|
return $client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findPhonetically($clientName)
|
||||||
|
{
|
||||||
|
$clientNameMeta = metaphone($clientName);
|
||||||
|
|
||||||
|
$map = [];
|
||||||
|
$max = SIMILAR_MIN_THRESHOLD;
|
||||||
|
$clientId = 0;
|
||||||
|
|
||||||
|
$clients = Client::scope()->get(['id', 'name', 'public_id']);
|
||||||
|
|
||||||
|
foreach ($clients as $client) {
|
||||||
|
if ( ! $client->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$map[$client->id] = $client;
|
||||||
|
$similar = similar_text($clientNameMeta, metaphone($client->name), $percent);
|
||||||
|
|
||||||
|
if ($percent > $max) {
|
||||||
|
$clientId = $client->id;
|
||||||
|
$max = $percent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$contacts = Contact::scope()->get(['client_id', 'first_name', 'last_name', 'public_id']);
|
||||||
|
|
||||||
|
foreach ($contacts as $contact) {
|
||||||
|
if ( ! $contact->getFullName() || ! isset($map[$contact->client_id])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$similar = similar_text($clientNameMeta, metaphone($contact->getFullName()), $percent);
|
||||||
|
|
||||||
|
if ($percent > $max) {
|
||||||
|
$clientId = $contact->client_id;
|
||||||
|
$max = $percent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($clientId && isset($map[$clientId])) ? $map[$clientId] : null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -262,6 +262,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
|
|
||||||
if ($invoice) {
|
if ($invoice) {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
$entityType = $invoice->getEntityType();
|
||||||
} elseif ($isNew) {
|
} elseif ($isNew) {
|
||||||
$entityType = ENTITY_INVOICE;
|
$entityType = ENTITY_INVOICE;
|
||||||
if (isset($data['is_recurring']) && filter_var($data['is_recurring'], FILTER_VALIDATE_BOOLEAN)) {
|
if (isset($data['is_recurring']) && filter_var($data['is_recurring'], FILTER_VALIDATE_BOOLEAN)) {
|
||||||
@ -270,6 +271,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$entityType = ENTITY_QUOTE;
|
$entityType = ENTITY_QUOTE;
|
||||||
}
|
}
|
||||||
$invoice = $account->createInvoice($entityType, $data['client_id']);
|
$invoice = $account->createInvoice($entityType, $data['client_id']);
|
||||||
|
$invoice->invoice_date = date_create()->format('Y-m-d');
|
||||||
if (isset($data['has_tasks']) && filter_var($data['has_tasks'], FILTER_VALIDATE_BOOLEAN)) {
|
if (isset($data['has_tasks']) && filter_var($data['has_tasks'], FILTER_VALIDATE_BOOLEAN)) {
|
||||||
$invoice->has_tasks = true;
|
$invoice->has_tasks = true;
|
||||||
}
|
}
|
||||||
|
@ -56,4 +56,34 @@ class ProductRepository extends BaseRepository
|
|||||||
return $product;
|
return $product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findPhonetically($productName)
|
||||||
|
{
|
||||||
|
$productNameMeta = metaphone($productName);
|
||||||
|
|
||||||
|
$map = [];
|
||||||
|
$max = SIMILAR_MIN_THRESHOLD;
|
||||||
|
$productId = 0;
|
||||||
|
|
||||||
|
$products = Product::scope()
|
||||||
|
->with('default_tax_rate')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($products as $product) {
|
||||||
|
if ( ! $product->product_key) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$map[$product->id] = $product;
|
||||||
|
$similar = similar_text($productNameMeta, metaphone($product->product_key), $percent);
|
||||||
|
|
||||||
|
if ($percent > $max) {
|
||||||
|
$productId = $product->id;
|
||||||
|
$max = $percent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($productId && isset($map[$productId])) ? $map[$productId] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class InvoiceTransformer extends EntityTransformer
|
|||||||
public function includeInvoiceItems(Invoice $invoice)
|
public function includeInvoiceItems(Invoice $invoice)
|
||||||
{
|
{
|
||||||
$transformer = new InvoiceItemTransformer($this->account, $this->serializer);
|
$transformer = new InvoiceItemTransformer($this->account, $this->serializer);
|
||||||
return $this->includeCollection($invoice->invoice_items, $transformer, ENTITY_INVOICE_ITEMS);
|
return $this->includeCollection($invoice->invoice_items, $transformer, ENTITY_INVOICE_ITEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function includeInvitations(Invoice $invoice)
|
public function includeInvitations(Invoice $invoice)
|
||||||
|
@ -45,7 +45,7 @@ class EntityPolicy
|
|||||||
* @param $ownerUserId
|
* @param $ownerUserId
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function viewByOwner(User$user, $ownerUserId) {
|
public static function viewByOwner(User $user, $ownerUserId) {
|
||||||
return $user->hasPermission('view_all') || $user->id == $ownerUserId;
|
return $user->hasPermission('view_all') || $user->id == $ownerUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,11 @@ class ComposerServiceProvider extends ServiceProvider
|
|||||||
['accounts.details', 'clients.edit', 'payments.edit', 'invoices.edit', 'accounts.localization'],
|
['accounts.details', 'clients.edit', 'payments.edit', 'invoices.edit', 'accounts.localization'],
|
||||||
'App\Http\ViewComposers\TranslationComposer'
|
'App\Http\ViewComposers\TranslationComposer'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
view()->composer(
|
||||||
|
['header', 'tasks.edit'],
|
||||||
|
'App\Http\ViewComposers\AppLanguageComposer'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +32,7 @@ class BaseService
|
|||||||
$entities = $this->getRepo()->findByPublicIdsWithTrashed($ids);
|
$entities = $this->getRepo()->findByPublicIdsWithTrashed($ids);
|
||||||
|
|
||||||
foreach ($entities as $entity) {
|
foreach ($entities as $entity) {
|
||||||
if(Auth::user()->can('edit', $entity)){
|
if (Auth::user()->can('edit', $entity)) {
|
||||||
$this->getRepo()->$action($entity);
|
$this->getRepo()->$action($entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ use Auth;
|
|||||||
use Utils;
|
use Utils;
|
||||||
use parsecsv;
|
use parsecsv;
|
||||||
use Session;
|
use Session;
|
||||||
use Validator;
|
|
||||||
use League\Fractal\Manager;
|
use League\Fractal\Manager;
|
||||||
use App\Ninja\Repositories\ContactRepository;
|
use App\Ninja\Repositories\ContactRepository;
|
||||||
use App\Ninja\Repositories\ClientRepository;
|
use App\Ninja\Repositories\ClientRepository;
|
||||||
@ -141,7 +140,7 @@ class ImportService
|
|||||||
|
|
||||||
foreach ($json['clients'] as $jsonClient) {
|
foreach ($json['clients'] as $jsonClient) {
|
||||||
|
|
||||||
if ($this->validate($jsonClient, ENTITY_CLIENT) === true) {
|
if (EntityModel::validate($jsonClient, ENTITY_CLIENT) === true) {
|
||||||
$client = $this->clientRepo->save($jsonClient);
|
$client = $this->clientRepo->save($jsonClient);
|
||||||
$this->addSuccess($client);
|
$this->addSuccess($client);
|
||||||
} else {
|
} else {
|
||||||
@ -151,7 +150,7 @@ class ImportService
|
|||||||
|
|
||||||
foreach ($jsonClient['invoices'] as $jsonInvoice) {
|
foreach ($jsonClient['invoices'] as $jsonInvoice) {
|
||||||
$jsonInvoice['client_id'] = $client->id;
|
$jsonInvoice['client_id'] = $client->id;
|
||||||
if ($this->validate($jsonInvoice, ENTITY_INVOICE) === true) {
|
if (EntityModel::validate($jsonInvoice, ENTITY_INVOICE) === true) {
|
||||||
$invoice = $this->invoiceRepo->save($jsonInvoice);
|
$invoice = $this->invoiceRepo->save($jsonInvoice);
|
||||||
$this->addSuccess($invoice);
|
$this->addSuccess($invoice);
|
||||||
} else {
|
} else {
|
||||||
@ -162,7 +161,7 @@ class ImportService
|
|||||||
foreach ($jsonInvoice['payments'] as $jsonPayment) {
|
foreach ($jsonInvoice['payments'] as $jsonPayment) {
|
||||||
$jsonPayment['client_id'] = $jsonPayment['client'] = $client->id; // TODO: change to client_id once views are updated
|
$jsonPayment['client_id'] = $jsonPayment['client'] = $client->id; // TODO: change to client_id once views are updated
|
||||||
$jsonPayment['invoice_id'] = $jsonPayment['invoice'] = $invoice->id; // TODO: change to invoice_id once views are updated
|
$jsonPayment['invoice_id'] = $jsonPayment['invoice'] = $invoice->id; // TODO: change to invoice_id once views are updated
|
||||||
if ($this->validate($jsonPayment, ENTITY_PAYMENT) === true) {
|
if (EntityModel::validate($jsonPayment, ENTITY_PAYMENT) === true) {
|
||||||
$payment = $this->paymentRepo->save($jsonPayment);
|
$payment = $this->paymentRepo->save($jsonPayment);
|
||||||
$this->addSuccess($payment);
|
$this->addSuccess($payment);
|
||||||
} else {
|
} else {
|
||||||
@ -280,7 +279,7 @@ class ImportService
|
|||||||
$data['invoice_number'] = $account->getNextInvoiceNumber($invoice);
|
$data['invoice_number'] = $account->getNextInvoiceNumber($invoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->validate($data, $entityType) !== true) {
|
if (EntityModel::validate($data, $entityType) !== true) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,26 +395,6 @@ class ImportService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $data
|
|
||||||
* @param $entityType
|
|
||||||
* @return bool|string
|
|
||||||
*/
|
|
||||||
private function validate($data, $entityType)
|
|
||||||
{
|
|
||||||
$requestClass = 'App\\Http\\Requests\\Create' . ucwords($entityType) . 'Request';
|
|
||||||
$request = new $requestClass();
|
|
||||||
$request->setUserResolver(function() { return Auth::user(); });
|
|
||||||
$request->replace($data);
|
|
||||||
|
|
||||||
$validator = Validator::make($data, $request->rules());
|
|
||||||
|
|
||||||
if ($validator->fails()) {
|
|
||||||
return $validator->messages()->first();
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $files
|
* @param array $files
|
||||||
|
@ -57,6 +57,21 @@ class PaymentService extends BaseService
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($credits = $client->credits->sum('balance')) {
|
||||||
|
$balance = $invoice->balance;
|
||||||
|
$amount = min($credits, $balance);
|
||||||
|
$data = [
|
||||||
|
'payment_type_id' => PAYMENT_TYPE_CREDIT,
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'client_id' => $client->id,
|
||||||
|
'amount' => $amount,
|
||||||
|
];
|
||||||
|
$payment = $this->paymentRepo->save($data);
|
||||||
|
if ($amount == $balance) {
|
||||||
|
return $payment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$paymentDriver = $account->paymentDriver($invitation, GATEWAY_TYPE_TOKEN);
|
$paymentDriver = $account->paymentDriver($invitation, GATEWAY_TYPE_TOKEN);
|
||||||
|
|
||||||
if ( ! $paymentDriver) {
|
if ( ! $paymentDriver) {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jquery": "1.11.3",
|
"jquery": "1.11.3",
|
||||||
"bootstrap": "3.3.1",
|
"bootstrap": "3.3.1",
|
||||||
|
"bootstrap-combobox": "1.1.5",
|
||||||
"jquery-ui": "1.11.2",
|
"jquery-ui": "1.11.2",
|
||||||
"datatables": "1.10.4",
|
"datatables": "1.10.4",
|
||||||
"datatables-bootstrap3": "*",
|
"datatables-bootstrap3": "*",
|
||||||
@ -27,7 +28,8 @@
|
|||||||
"datetimepicker": "~2.4.5",
|
"datetimepicker": "~2.4.5",
|
||||||
"stacktrace-js": "~1.0.1",
|
"stacktrace-js": "~1.0.1",
|
||||||
"fuse.js": "~2.0.2",
|
"fuse.js": "~2.0.2",
|
||||||
"dropzone": "~4.3.0"
|
"dropzone": "~4.3.0",
|
||||||
|
"sweetalert": "~1.1.3"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"jquery": "~1.11"
|
"jquery": "~1.11"
|
||||||
|
@ -13,6 +13,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
|
"php": ">=5.5.9",
|
||||||
|
"ext-mcrypt": "*",
|
||||||
|
"ext-gmp": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
"turbo124/laravel-push-notification": "dev-laravel5",
|
"turbo124/laravel-push-notification": "dev-laravel5",
|
||||||
"omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
|
"omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
|
||||||
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
|
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
|
||||||
|
@ -41,8 +41,7 @@ class AddPageSize extends Migration
|
|||||||
|
|
||||||
Schema::table('expenses', function ($table) {
|
Schema::table('expenses', function ($table) {
|
||||||
$table->unsignedInteger('expense_category_id')->nullable()->index();
|
$table->unsignedInteger('expense_category_id')->nullable()->index();
|
||||||
|
//$table->foreign('expense_category_id')->references('id')->on('expense_categories')->onDelete('cascade');
|
||||||
$table->foreign('expense_category_id')->references('id')->on('expense_categories')->onDelete('cascade');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ class PaymentsChanges extends Migration
|
|||||||
$table->string('email')->nullable();
|
$table->string('email')->nullable();
|
||||||
|
|
||||||
$table->unsignedInteger('payment_method_id')->nullable();
|
$table->unsignedInteger('payment_method_id')->nullable();
|
||||||
$table->foreign('payment_method_id')->references('id')->on('payment_methods');
|
//$table->foreign('payment_method_id')->references('id')->on('payment_methods');
|
||||||
});
|
});
|
||||||
|
|
||||||
Schema::table('invoices', function($table)
|
Schema::table('invoices', function($table)
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddSupportForBots extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('security_codes', function($table)
|
||||||
|
{
|
||||||
|
$table->increments('id');
|
||||||
|
$table->unsignedInteger('account_id')->index();
|
||||||
|
$table->unsignedInteger('user_id')->nullable();
|
||||||
|
$table->unsignedInteger('contact_id')->nullable();
|
||||||
|
$table->smallInteger('attempts');
|
||||||
|
$table->string('code')->nullable();
|
||||||
|
$table->string('bot_user_id')->unique();
|
||||||
|
$table->timestamp('created_at')->useCurrent();
|
||||||
|
|
||||||
|
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||||
|
$table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade');
|
||||||
|
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('users', function($table)
|
||||||
|
{
|
||||||
|
$table->string('bot_user_id')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('contacts', function($table)
|
||||||
|
{
|
||||||
|
$table->string('bot_user_id')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('accounts', function($table)
|
||||||
|
{
|
||||||
|
$table->boolean('include_item_taxes_inline')->default(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('security_codes');
|
||||||
|
|
||||||
|
Schema::table('users', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('bot_user_id');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('contacts', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('bot_user_id');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('accounts', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('include_item_taxes_inline');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -55,7 +55,7 @@ class DateFormatsSeeder extends Seeder
|
|||||||
];
|
];
|
||||||
|
|
||||||
foreach ($formats as $format) {
|
foreach ($formats as $format) {
|
||||||
$record = DatetimeFormat::whereFormat($format['format'])->first();
|
$record = DatetimeFormat::whereRaw("BINARY `format`= ?", array($format['format']))->first();
|
||||||
if ($record) {
|
if ($record) {
|
||||||
$record->format_moment = $format['format_moment'];
|
$record->format_moment = $format['format_moment'];
|
||||||
$record->save();
|
$record->save();
|
||||||
|
100
gulpfile.js
@ -1,16 +1,96 @@
|
|||||||
var elixir = require('laravel-elixir');
|
var elixir = require('laravel-elixir');
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* Set Elixir Source Maps
|
||||||
| Elixir Asset Management
|
*
|
||||||
|--------------------------------------------------------------------------
|
* @type {boolean}
|
||||||
|
|
|
||||||
| Elixir provides a clean, fluent API for defining some basic Gulp tasks
|
|
||||||
| for your Laravel application. By default, we are compiling the Less
|
|
||||||
| file for our application, as well as publishing vendor resources.
|
|
||||||
|
|
|
||||||
*/
|
*/
|
||||||
|
elixir.config.sourcemaps = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuring assets path.
|
||||||
|
* Explicitly setting it to empty, as we're not using Laravels resources/assets folder
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
elixir.config.assetsPath = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuring Javascript assets path.
|
||||||
|
* Explicitly setting it to empty, as we're not using Laravels resources/assets/js folder
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
elixir.config.js.folder = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuring CSS assets path.
|
||||||
|
* Explicitly setting it to empty, as we're not using Laravels resources/assets/css folder
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
elixir.config.css.folder = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all CSS comments
|
||||||
|
*
|
||||||
|
* @type {{discardComments: {removeAll: boolean}}}
|
||||||
|
*/
|
||||||
|
elixir.config.css.minifier.pluginOptions = {
|
||||||
|
discardComments: {
|
||||||
|
removeAll: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory for bower source files.
|
||||||
|
* If changing this, please also see .bowerrc
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
var bowerDir = 'public/vendor';
|
||||||
|
|
||||||
elixir(function(mix) {
|
elixir(function(mix) {
|
||||||
mix.less('app.less');
|
|
||||||
|
/**
|
||||||
|
* CSS configuration
|
||||||
|
*/
|
||||||
|
mix.styles([
|
||||||
|
bowerDir + '/bootstrap/dist/css/bootstrap.css',
|
||||||
|
bowerDir + '/font-awesome/css/font-awesome.css',
|
||||||
|
bowerDir + '/datatables/media/css/jquery.dataTables.css',
|
||||||
|
bowerDir + '/datatables-bootstrap3/BS3/assets/css/datatables.css',
|
||||||
|
'public/css/bootstrap-combobox.css',
|
||||||
|
'public/css/public.style.css'
|
||||||
|
], 'public/css/built.public.css');
|
||||||
|
|
||||||
|
mix.styles([
|
||||||
|
bowerDir + '/bootstrap/dist/css/bootstrap.css',
|
||||||
|
bowerDir + '/bootstrap-datepicker/dist/css/bootstrap-datepicker3.css',
|
||||||
|
bowerDir + '/datatables/media/css/jquery.dataTables.css',
|
||||||
|
bowerDir + '/datatables-bootstrap3/BS3/assets/css/datatables.css',
|
||||||
|
bowerDir + '/font-awesome/css/font-awesome.css',
|
||||||
|
bowerDir + '/dropzone/dist/dropzone.css',
|
||||||
|
bowerDir + '/spectrum/spectrum.css',
|
||||||
|
bowerDir + '/sweetalert/dist/sweetalert.css',
|
||||||
|
'public/css/bootstrap-combobox.css',
|
||||||
|
'public/css/typeahead.js-bootstrap.css',
|
||||||
|
'public/css/style.css'
|
||||||
|
], 'public/css/built.css');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JS configuration
|
||||||
|
*/
|
||||||
|
mix.scripts(['resources/assets/js/Chart.js'], 'public/js/Chart.min.js')
|
||||||
|
.scripts(['resources/assets/js/d3.js'], 'public/js/d3.min.js');
|
||||||
|
|
||||||
|
mix.scripts([
|
||||||
|
'public/js/pdf_viewer.js',
|
||||||
|
'public/js/compatibility.js',
|
||||||
|
//'public/js/pdfmake.min.js',
|
||||||
|
'public/js/pdfmake.js',
|
||||||
|
'public/js/vfs.js'
|
||||||
|
], 'public/pdf.built.js');
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"grunt-contrib-uglify": "~0.2.2",
|
"grunt-contrib-uglify": "~0.2.2",
|
||||||
"grunt-dump-dir": "^0.1.2",
|
"grunt-dump-dir": "^0.1.2",
|
||||||
"gulp": "^3.8.8",
|
"gulp": "^3.8.8",
|
||||||
"laravel-elixir": "*"
|
"laravel-elixir": "^6.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"grunt-dump-dir": "^0.1.2"
|
"grunt-dump-dir": "^0.1.2"
|
||||||
|
BIN
public/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
public/android-chrome-512x512.png
Normal file
After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 12 KiB |
1
public/built.js.map
Normal file
3
public/css/app.min.css
vendored
Normal file
1
public/css/app.min.css.map
Normal file
1
public/css/bootstrap.min.css.map
Normal file
3235
public/css/built.css
vendored
1
public/css/built.css.map
Normal file
21
public/css/built.min.css
vendored
Normal file
1
public/css/built.min.css.map
Normal file
971
public/css/built.public.css
vendored
1
public/css/built.public.css.map
Normal file
14
public/css/built.public.min.css
vendored
Normal file
1
public/css/built.public.min.css.map
Normal file
2
public/css/customCss.min.css
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.customContainer{padding:40px 0;margin:0!important;background:-webkit-linear-gradient(#f5f5f5,#fff)}.customFontHead{font-size:20px;text-align:center}.customTextBorder{border-bottom:1px solid #c3c1c1;padding-bottom:5%;margin-bottom:5%}.customSubMenu{margin-left:2%}.customMenuOne{padding-left:5px;padding-right:5px}.shiftLeft{float:left}.customMenuDiv{padding-bottom:30px;float:left;width:100%}
|
||||||
|
/*# sourceMappingURL=customCss.min.css.map */
|
1
public/css/customCss.min.css.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["customCss.css"],"names":[],"mappings":"AAAA,iBACA,eAAA,AACA,mBAAA,AACA,gDAAA,CACA,AACA,gBACA,eAAA,AACA,iBAAA,CACA,AACA,kBACA,gCAAA,AACA,kBAAA,AACA,gBAAA,CACA,AACA,eACA,cAAA,CACA,AACA,eACA,iBAAA,AACA,iBAAA,CACA,AACA,WACA,UAAA,CACA,AACA,eACA,oBAAA,AACA,WAAA,AACA,UAAA,CACA","file":"customCss.min.css","sourcesContent":[".customContainer{\n\tpadding: 40px 0;\n\tmargin: 0px 0 !important;\n\tbackground: -webkit-linear-gradient(rgb(245, 245, 245), white);\n}\t\n.customFontHead{\n\tfont-size: 20px;\n\ttext-align: center;\n}\t\n.customTextBorder{\n\tborder-bottom: 1px solid rgb(195, 193, 193);\n\tpadding-bottom: 5%;\n\tmargin-bottom: 5%;\n}\n.customSubMenu{\n\tmargin-left: 2%;\n}\n.customMenuOne{\n\tpadding-left: 5px;\n\tpadding-right: 5px;\n}\n.shiftLeft{\n\tfloat: left;\n}\n.customMenuDiv{\n\tpadding-bottom: 30px;\n\tfloat: left;\n\twidth: 100%;\n}"],"sourceRoot":"/source/"}
|
893
public/css/img/jsoneditor-icons.svg
Normal file
@ -0,0 +1,893 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="216"
|
||||||
|
height="144"
|
||||||
|
id="svg4136"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r"
|
||||||
|
sodipodi:docname="jsoneditor-icons.svg">
|
||||||
|
<title
|
||||||
|
id="title6512">JSON Editor Icons</title>
|
||||||
|
<metadata
|
||||||
|
id="metadata4148">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title>JSON Editor Icons</dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs4146" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1028"
|
||||||
|
id="namedview4144"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:zoom="4"
|
||||||
|
inkscape:cx="97.217248"
|
||||||
|
inkscape:cy="59.950227"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg4136"
|
||||||
|
showguides="false"
|
||||||
|
borderlayer="false"
|
||||||
|
inkscape:showpageshadow="true"
|
||||||
|
showborder="true">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4640"
|
||||||
|
empspacing="24" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
|
||||||
|
<g
|
||||||
|
id="g4394">
|
||||||
|
<rect
|
||||||
|
x="4"
|
||||||
|
y="4"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
id="svg_1"
|
||||||
|
style="fill:#1aae1c;fill-opacity:1;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ec3f29;fill-opacity:0.94117647;stroke:none;stroke-width:0"
|
||||||
|
x="28.000006"
|
||||||
|
y="3.999995"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
id="svg_1-7" />
|
||||||
|
<rect
|
||||||
|
id="rect4165"
|
||||||
|
height="16"
|
||||||
|
width="16"
|
||||||
|
y="3.999995"
|
||||||
|
x="52.000004"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
x="172.00002"
|
||||||
|
y="3.9999852"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
id="rect4175" />
|
||||||
|
<rect
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
x="196"
|
||||||
|
y="3.999995"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
id="rect4175-3" />
|
||||||
|
<g
|
||||||
|
style="stroke:none"
|
||||||
|
id="g4299">
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
id="svg_1-1"
|
||||||
|
height="1.9999986"
|
||||||
|
width="9.9999924"
|
||||||
|
y="10.999998"
|
||||||
|
x="7.0000048" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
id="svg_1-1-1"
|
||||||
|
height="9.9999838"
|
||||||
|
width="1.9999955"
|
||||||
|
y="7.0000114"
|
||||||
|
x="11.000005" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
style="stroke:none"
|
||||||
|
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,19.029435,12.000001)"
|
||||||
|
id="g4299-3">
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
id="svg_1-1-0"
|
||||||
|
height="1.9999986"
|
||||||
|
width="9.9999924"
|
||||||
|
y="10.999998"
|
||||||
|
x="7.0000048" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
id="svg_1-1-1-9"
|
||||||
|
height="9.9999838"
|
||||||
|
width="1.9999955"
|
||||||
|
y="7.0000114"
|
||||||
|
x="11.000005" />
|
||||||
|
</g>
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||||
|
x="55.000004"
|
||||||
|
y="7.0000048"
|
||||||
|
width="6.9999909"
|
||||||
|
height="6.9999905"
|
||||||
|
id="svg_1-7-5" />
|
||||||
|
<rect
|
||||||
|
id="rect4354"
|
||||||
|
height="6.9999905"
|
||||||
|
width="6.9999909"
|
||||||
|
y="10.00001"
|
||||||
|
x="58"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#3c80df;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647"
|
||||||
|
x="58.000004"
|
||||||
|
y="10.000005"
|
||||||
|
width="6.9999909"
|
||||||
|
height="6.9999905"
|
||||||
|
id="svg_1-7-5-7" />
|
||||||
|
<g
|
||||||
|
id="g4378">
|
||||||
|
<rect
|
||||||
|
id="svg_1-7-5-3"
|
||||||
|
height="1.9999965"
|
||||||
|
width="7.9999909"
|
||||||
|
y="10.999999"
|
||||||
|
x="198"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||||
|
x="198"
|
||||||
|
y="7.0000005"
|
||||||
|
width="11.999995"
|
||||||
|
height="1.9999946"
|
||||||
|
id="rect4374" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||||
|
x="198"
|
||||||
|
y="14.999996"
|
||||||
|
width="3.9999928"
|
||||||
|
height="1.9999995"
|
||||||
|
id="rect4376" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4383"
|
||||||
|
transform="matrix(1,0,0,-1,-23.999995,23.999995)">
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||||
|
x="198"
|
||||||
|
y="10.999999"
|
||||||
|
width="7.9999909"
|
||||||
|
height="1.9999965"
|
||||||
|
id="rect4385" />
|
||||||
|
<rect
|
||||||
|
id="rect4387"
|
||||||
|
height="1.9999946"
|
||||||
|
width="11.999995"
|
||||||
|
y="7.0000005"
|
||||||
|
x="198"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="rect4389"
|
||||||
|
height="1.9999995"
|
||||||
|
width="3.9999928"
|
||||||
|
y="14.999996"
|
||||||
|
x="198"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||||
|
</g>
|
||||||
|
<rect
|
||||||
|
y="3.9999199"
|
||||||
|
x="76"
|
||||||
|
height="16"
|
||||||
|
width="16"
|
||||||
|
id="rect3754-4"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4351"
|
||||||
|
d="m 85.10447,6.0157384 -0.0156,1.4063 c 3.02669,-0.2402 0.33008,3.6507996 2.48438,4.5780996 -2.18694,1.0938 0.49191,4.9069 -2.45313,4.5781 l -0.0156,1.4219 c 5.70828,0.559 1.03264,-5.1005 4.70313,-5.2656 l 0,-1.4063 c -3.61303,-0.027 1.11893,-5.7069996 -4.70313,-5.3124996 z"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4351-9"
|
||||||
|
d="m 82.78125,5.9984384 0.0156,1.4063 c -3.02668,-0.2402 -0.33007,3.6506996 -2.48437,4.5780996 2.18694,1.0938 -0.49192,4.9069 2.45312,4.5781 l 0.0156,1.4219 c -5.70827,0.559 -1.03263,-5.1004 -4.70312,-5.2656 l 0,-1.4063 c 3.61303,-0.027 -1.11894,-5.7070996 4.70312,-5.3124996 z"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
y="3.9999199"
|
||||||
|
x="100"
|
||||||
|
height="16"
|
||||||
|
width="16"
|
||||||
|
id="rect3754-25"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path2987"
|
||||||
|
d="m 103.719,5.6719384 0,12.7187996 3.03125,0 0,-1.5313 -1.34375,0 0,-9.6249996 1.375,0 0,-1.5625 z"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path2987-1"
|
||||||
|
d="m 112.2185,5.6721984 0,12.7187996 -3.03125,0 0,-1.5313 1.34375,0 0,-9.6249996 -1.375,0 0,-1.5625 z"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||||
|
<rect
|
||||||
|
y="3.9999199"
|
||||||
|
x="124"
|
||||||
|
height="16"
|
||||||
|
width="16"
|
||||||
|
id="rect3754-73"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3780"
|
||||||
|
d="m 126.2824,17.602938 1.78957,0 1.14143,-2.8641 5.65364,0 1.14856,2.8641 1.76565,0 -4.78687,-11.1610996 -1.91903,0 z"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3782"
|
||||||
|
d="m 129.72704,13.478838 4.60852,0.01 -2.30426,-5.5497996 z"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||||
|
<rect
|
||||||
|
y="3.9999199"
|
||||||
|
x="148"
|
||||||
|
height="16"
|
||||||
|
width="16"
|
||||||
|
id="rect3754-35"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5008-2"
|
||||||
|
d="m 156.47655,5.8917384 0,2.1797 0.46093,2.3983996 1.82813,0 0.39844,-2.3983996 0,-2.1797 z"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5008-2-8"
|
||||||
|
d="m 152.51561,5.8906384 0,2.1797 0.46094,2.3983996 1.82812,0 0.39844,-2.3983996 0,-2.1797 z"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||||
|
</g>
|
||||||
|
<rect
|
||||||
|
x="4"
|
||||||
|
y="27.999994"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
id="rect4432"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
x="28.000006"
|
||||||
|
y="27.99999"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
id="rect4434" />
|
||||||
|
<rect
|
||||||
|
id="rect4436"
|
||||||
|
height="16"
|
||||||
|
width="16"
|
||||||
|
y="27.99999"
|
||||||
|
x="52.000004"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;stroke:#000000;stroke-width:0"
|
||||||
|
x="172.00002"
|
||||||
|
y="27.999981"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
id="rect4446" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;stroke:#000000;stroke-width:0"
|
||||||
|
x="196"
|
||||||
|
y="27.99999"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
id="rect4448" />
|
||||||
|
<g
|
||||||
|
id="g4466"
|
||||||
|
style="stroke:none"
|
||||||
|
transform="translate(0,23.999995)">
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
id="rect4468"
|
||||||
|
height="1.9999986"
|
||||||
|
width="9.9999924"
|
||||||
|
y="10.999998"
|
||||||
|
x="7.0000048" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
id="rect4470"
|
||||||
|
height="9.9999838"
|
||||||
|
width="1.9999955"
|
||||||
|
y="7.0000114"
|
||||||
|
x="11.000005" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,19.029435,35.999996)"
|
||||||
|
id="g4472"
|
||||||
|
style="stroke:none">
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
id="rect4474"
|
||||||
|
height="1.9999986"
|
||||||
|
width="9.9999924"
|
||||||
|
y="10.999998"
|
||||||
|
x="7.0000048" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||||
|
id="rect4476"
|
||||||
|
height="9.9999838"
|
||||||
|
width="1.9999955"
|
||||||
|
y="7.0000114"
|
||||||
|
x="11.000005" />
|
||||||
|
</g>
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||||
|
x="55.000004"
|
||||||
|
y="31"
|
||||||
|
width="6.9999909"
|
||||||
|
height="6.9999905"
|
||||||
|
id="rect4478" />
|
||||||
|
<rect
|
||||||
|
id="rect4480"
|
||||||
|
height="6.9999905"
|
||||||
|
width="6.9999909"
|
||||||
|
y="34.000008"
|
||||||
|
x="58"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#d3d3d3;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
x="58.000004"
|
||||||
|
y="34.000004"
|
||||||
|
width="6.9999909"
|
||||||
|
height="6.9999905"
|
||||||
|
id="rect4482" />
|
||||||
|
<g
|
||||||
|
id="g4484"
|
||||||
|
transform="translate(0,23.999995)">
|
||||||
|
<rect
|
||||||
|
id="rect4486"
|
||||||
|
height="1.9999965"
|
||||||
|
width="7.9999909"
|
||||||
|
y="10.999999"
|
||||||
|
x="198"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||||
|
x="198"
|
||||||
|
y="7.0000005"
|
||||||
|
width="11.999995"
|
||||||
|
height="1.9999946"
|
||||||
|
id="rect4488" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||||
|
x="198"
|
||||||
|
y="14.999996"
|
||||||
|
width="3.9999928"
|
||||||
|
height="1.9999995"
|
||||||
|
id="rect4490" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4492"
|
||||||
|
transform="matrix(1,0,0,-1,-23.999995,47.99999)">
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||||
|
x="198"
|
||||||
|
y="10.999999"
|
||||||
|
width="7.9999909"
|
||||||
|
height="1.9999965"
|
||||||
|
id="rect4494" />
|
||||||
|
<rect
|
||||||
|
id="rect4496"
|
||||||
|
height="1.9999946"
|
||||||
|
width="11.999995"
|
||||||
|
y="7.0000005"
|
||||||
|
x="198"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="rect4498"
|
||||||
|
height="1.9999995"
|
||||||
|
width="3.9999928"
|
||||||
|
y="14.999996"
|
||||||
|
x="198"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||||
|
</g>
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||||
|
id="rect3754-8"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
x="76"
|
||||||
|
y="27.99992" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 85.10448,30.015537 -0.0156,1.4063 c 3.02668,-0.2402 0.33007,3.6508 2.48438,4.5781 -2.18695,1.0938 0.49191,4.90688 -2.45313,4.57808 l -0.0156,1.4219 c 5.70827,0.559 1.03263,-5.10048 4.70313,-5.26558 l 0,-1.4063 c -3.61304,-0.027 1.11893,-5.707 -4.70313,-5.3125 z"
|
||||||
|
id="path4351-1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 82.78126,29.998237 0.0156,1.4063 c -3.02668,-0.2402 -0.33008,3.6507 -2.48438,4.5781 2.18694,1.0938 -0.49191,4.90688 2.45313,4.57808 l 0.0156,1.4219 c -5.70828,0.559 -1.03264,-5.10038 -4.70313,-5.26558 l 0,-1.4063 c 3.61303,-0.027 -1.11893,-5.7071 4.70313,-5.3125 z"
|
||||||
|
id="path4351-9-5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||||
|
id="rect3754-65"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
x="100"
|
||||||
|
y="27.99992" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||||
|
d="m 103.719,29.671937 0,12.71878 3.03125,0 0,-1.5313 -1.34375,0 0,-9.62498 1.375,0 0,-1.5625 z"
|
||||||
|
id="path2987-8"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||||
|
d="m 112.2185,29.671937 0,12.71878 -3.03125,0 0,-1.5313 1.34375,0 0,-9.62498 -1.375,0 0,-1.5625 z"
|
||||||
|
id="path2987-1-9"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||||
|
id="rect3754-92"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
x="124"
|
||||||
|
y="27.99992" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||||
|
d="m 126.2824,41.602917 1.78957,0 1.14143,-2.86408 5.65364,0 1.14856,2.86408 1.76565,0 -4.78687,-11.16108 -1.91902,0 z"
|
||||||
|
id="path3780-9"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||||
|
d="m 129.72704,37.478837 4.60852,0.01 -2.30426,-5.5498 z"
|
||||||
|
id="path3782-2"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||||
|
id="rect3754-47"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
x="148"
|
||||||
|
y="27.99992" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||||
|
d="m 156.47656,29.891737 0,2.1797 0.46093,2.3984 1.82813,0 0.39844,-2.3984 0,-2.1797 z"
|
||||||
|
id="path5008-2-1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||||
|
d="m 152.51562,29.890637 0,2.1797 0.46094,2.3984 1.82812,0 0.39844,-2.3984 0,-2.1797 z"
|
||||||
|
id="path5008-2-8-8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc" />
|
||||||
|
<rect
|
||||||
|
id="svg_1-7-2"
|
||||||
|
height="1.9999961"
|
||||||
|
width="11.999996"
|
||||||
|
y="64"
|
||||||
|
x="54"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="svg_1-7-2-2"
|
||||||
|
height="2.9999905"
|
||||||
|
width="2.9999907"
|
||||||
|
y="52"
|
||||||
|
x="80.000008"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||||
|
x="85.000008"
|
||||||
|
y="52"
|
||||||
|
width="2.9999907"
|
||||||
|
height="2.9999905"
|
||||||
|
id="rect4561" />
|
||||||
|
<rect
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||||
|
x="80.000008"
|
||||||
|
y="58"
|
||||||
|
width="2.9999907"
|
||||||
|
height="2.9999905"
|
||||||
|
id="rect4563" />
|
||||||
|
<rect
|
||||||
|
id="rect4565"
|
||||||
|
height="2.9999905"
|
||||||
|
width="2.9999907"
|
||||||
|
y="58"
|
||||||
|
x="85.000008"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="rect4567"
|
||||||
|
height="2.9999905"
|
||||||
|
width="2.9999907"
|
||||||
|
y="64"
|
||||||
|
x="80.000008"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||||
|
x="85.000008"
|
||||||
|
y="64"
|
||||||
|
width="2.9999907"
|
||||||
|
height="2.9999905"
|
||||||
|
id="rect4569" />
|
||||||
|
<circle
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
id="path4571"
|
||||||
|
cx="110.06081"
|
||||||
|
cy="57.939209"
|
||||||
|
r="4.7438836" />
|
||||||
|
<rect
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||||
|
x="116.64566"
|
||||||
|
y="-31.79752"
|
||||||
|
width="4.229713"
|
||||||
|
height="6.4053884"
|
||||||
|
id="rect4563-2"
|
||||||
|
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" />
|
||||||
|
<path
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 125,56 138.77027,56.095 132,64 Z"
|
||||||
|
id="path4613"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4615"
|
||||||
|
d="M 149,64 162.77027,63.905 156,56 Z"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||||
|
x="54"
|
||||||
|
y="53"
|
||||||
|
width="11.999996"
|
||||||
|
height="1.9999961"
|
||||||
|
id="rect4638" />
|
||||||
|
<rect
|
||||||
|
id="svg_1-7-2-24"
|
||||||
|
height="1.9999957"
|
||||||
|
width="12.99999"
|
||||||
|
y="-56"
|
||||||
|
x="53"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||||
|
transform="matrix(0,1,-1,0,0,0)" />
|
||||||
|
<rect
|
||||||
|
transform="matrix(0,1,-1,0,0,0)"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||||
|
x="53"
|
||||||
|
y="-66"
|
||||||
|
width="12.99999"
|
||||||
|
height="1.9999957"
|
||||||
|
id="rect4657" />
|
||||||
|
<rect
|
||||||
|
id="rect4659"
|
||||||
|
height="0.99999291"
|
||||||
|
width="11.999999"
|
||||||
|
y="57"
|
||||||
|
x="54"
|
||||||
|
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||||
|
x="54"
|
||||||
|
y="88.000122"
|
||||||
|
width="11.999996"
|
||||||
|
height="1.9999961"
|
||||||
|
id="rect4661" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||||
|
x="80.000008"
|
||||||
|
y="76.000122"
|
||||||
|
width="2.9999907"
|
||||||
|
height="2.9999905"
|
||||||
|
id="rect4663" />
|
||||||
|
<rect
|
||||||
|
id="rect4665"
|
||||||
|
height="2.9999905"
|
||||||
|
width="2.9999907"
|
||||||
|
y="76.000122"
|
||||||
|
x="85.000008"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
id="rect4667"
|
||||||
|
height="2.9999905"
|
||||||
|
width="2.9999907"
|
||||||
|
y="82.000122"
|
||||||
|
x="80.000008"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||||
|
x="85.000008"
|
||||||
|
y="82.000122"
|
||||||
|
width="2.9999907"
|
||||||
|
height="2.9999905"
|
||||||
|
id="rect4669" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||||
|
x="80.000008"
|
||||||
|
y="88.000122"
|
||||||
|
width="2.9999907"
|
||||||
|
height="2.9999905"
|
||||||
|
id="rect4671" />
|
||||||
|
<rect
|
||||||
|
id="rect4673"
|
||||||
|
height="2.9999905"
|
||||||
|
width="2.9999907"
|
||||||
|
y="88.000122"
|
||||||
|
x="85.000008"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
||||||
|
<circle
|
||||||
|
r="4.7438836"
|
||||||
|
cy="81.939331"
|
||||||
|
cx="110.06081"
|
||||||
|
id="circle4675"
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
|
||||||
|
id="rect4677"
|
||||||
|
height="6.4053884"
|
||||||
|
width="4.229713"
|
||||||
|
y="-14.826816"
|
||||||
|
x="133.6163"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:#d3d3d3;stroke-width:0;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4679"
|
||||||
|
d="m 125,80.000005 13.77027,0.09499 L 132,87.999992 Z"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 149,88.0002 162.77027,87.9052 156,80.0002 Z"
|
||||||
|
id="path4681"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<rect
|
||||||
|
id="rect4683"
|
||||||
|
height="1.9999961"
|
||||||
|
width="11.999996"
|
||||||
|
y="77.000122"
|
||||||
|
x="54"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
transform="matrix(0,1,-1,0,0,0)"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||||
|
x="77.000122"
|
||||||
|
y="-56"
|
||||||
|
width="12.99999"
|
||||||
|
height="1.9999957"
|
||||||
|
id="rect4685" />
|
||||||
|
<rect
|
||||||
|
id="rect4687"
|
||||||
|
height="1.9999957"
|
||||||
|
width="12.99999"
|
||||||
|
y="-66"
|
||||||
|
x="77.000122"
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||||
|
transform="matrix(0,1,-1,0,0,0)" />
|
||||||
|
<rect
|
||||||
|
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||||
|
x="54"
|
||||||
|
y="81.000122"
|
||||||
|
width="11.999999"
|
||||||
|
height="0.99999291"
|
||||||
|
id="rect4689" />
|
||||||
|
<rect
|
||||||
|
id="rect4761-1"
|
||||||
|
height="1.9999945"
|
||||||
|
width="15.99999"
|
||||||
|
y="101"
|
||||||
|
x="76.000008"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="rect4761-0"
|
||||||
|
height="1.9999945"
|
||||||
|
width="15.99999"
|
||||||
|
y="105"
|
||||||
|
x="76.000008"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="rect4761-7"
|
||||||
|
height="1.9999945"
|
||||||
|
width="9"
|
||||||
|
y="109"
|
||||||
|
x="76.000008"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="rect4761-1-1"
|
||||||
|
height="1.9999945"
|
||||||
|
width="12"
|
||||||
|
y="125"
|
||||||
|
x="76.000008"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="rect4761-1-1-4"
|
||||||
|
height="1.9999945"
|
||||||
|
width="10"
|
||||||
|
y="137"
|
||||||
|
x="76.000008"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="rect4761-1-1-4-4"
|
||||||
|
height="1.9999945"
|
||||||
|
width="10"
|
||||||
|
y="129"
|
||||||
|
x="82"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||||
|
<rect
|
||||||
|
id="rect4761-1-1-4-4-3"
|
||||||
|
height="1.9999945"
|
||||||
|
width="9"
|
||||||
|
y="133"
|
||||||
|
x="82"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 36.398438,100.0254 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,100.5991 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1452 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533865,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550756,0 6.710442,-2.4113 7.650391,-5.9414 0.939949,-3.5301 -0.618463,-7.2736 -3.710938,-9.0703 -1.159678,-0.6738 -2.431087,-1.0231 -3.701171,-1.0625 z"
|
||||||
|
id="path4138" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 59.722656,99.9629 c -1.270084,0.039 -2.541493,0.3887 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5402 -3.710937,9.0703 0.939949,3.5301 4.09768,5.9414 7.648437,5.9414 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4056 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
|
||||||
|
id="path4138-1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 10.5,100 0,2 -2.4999996,0 L 12,107 l 4,-5 -2.5,0 0,-2 -3,0 z"
|
||||||
|
id="path3055-0-77" />
|
||||||
|
<path
|
||||||
|
style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.966;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 4.9850574,108.015 14.0298856,-0.03"
|
||||||
|
id="path5244-5-0-5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.966;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 4.9849874,132.015 14.0298866,-0.03"
|
||||||
|
id="path5244-5-0-5-8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 36.398438,123.9629 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,124.5366 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1453 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533864,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550757,0 6.710442,-2.4093 7.650391,-5.9394 0.939949,-3.5301 -0.618463,-7.2756 -3.710938,-9.0723 -1.159678,-0.6737 -2.431087,-1.0231 -3.701171,-1.0625 z"
|
||||||
|
id="path4138-12" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 59.722656,123.9629 c -1.270084,0.039 -2.541493,0.3888 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5422 -3.710937,9.0723 0.939949,3.5301 4.09768,5.9394 7.648437,5.9394 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4055 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
|
||||||
|
id="path4138-1-3" />
|
||||||
|
<path
|
||||||
|
id="path6191"
|
||||||
|
d="m 10.5,116 0,-2 -2.4999996,0 L 12,109 l 4,5 -2.5,0 0,2 -3,0 z"
|
||||||
|
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 10.5,129 0,-2 -2.4999996,0 L 12,122 l 4,5 -2.5,0 0,2 -3,0 z"
|
||||||
|
id="path6193" />
|
||||||
|
<path
|
||||||
|
id="path6195"
|
||||||
|
d="m 10.5,135 0,2 -2.4999996,0 L 12,142 l 4,-5 -2.5,0 0,-2 -3,0 z"
|
||||||
|
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
sodipodi:type="star"
|
||||||
|
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
id="path4500"
|
||||||
|
sodipodi:sides="3"
|
||||||
|
sodipodi:cx="11.55581"
|
||||||
|
sodipodi:cy="60.073242"
|
||||||
|
sodipodi:r1="5.1116104"
|
||||||
|
sodipodi:r2="2.5558052"
|
||||||
|
sodipodi:arg1="0"
|
||||||
|
sodipodi:arg2="1.0471976"
|
||||||
|
inkscape:flatsided="false"
|
||||||
|
inkscape:rounded="0"
|
||||||
|
inkscape:randomized="0"
|
||||||
|
d="m 16.66742,60.073242 -3.833708,2.213392 -3.8337072,2.213393 0,-4.426785 0,-4.426784 3.8337082,2.213392 z"
|
||||||
|
inkscape:transform-center-x="-1.2779026" />
|
||||||
|
<path
|
||||||
|
inkscape:transform-center-x="1.277902"
|
||||||
|
d="m -31.500004,60.073242 -3.833708,2.213392 -3.833707,2.213393 0,-4.426785 0,-4.426784 3.833707,2.213392 z"
|
||||||
|
inkscape:randomized="0"
|
||||||
|
inkscape:rounded="0"
|
||||||
|
inkscape:flatsided="false"
|
||||||
|
sodipodi:arg2="1.0471976"
|
||||||
|
sodipodi:arg1="0"
|
||||||
|
sodipodi:r2="2.5558052"
|
||||||
|
sodipodi:r1="5.1116104"
|
||||||
|
sodipodi:cy="60.073242"
|
||||||
|
sodipodi:cx="-36.611614"
|
||||||
|
sodipodi:sides="3"
|
||||||
|
id="path4502"
|
||||||
|
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
sodipodi:type="star"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
<path
|
||||||
|
d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z"
|
||||||
|
inkscape:randomized="0"
|
||||||
|
inkscape:rounded="0"
|
||||||
|
inkscape:flatsided="false"
|
||||||
|
sodipodi:arg2="1.0471976"
|
||||||
|
sodipodi:arg1="0"
|
||||||
|
sodipodi:r2="2.5558052"
|
||||||
|
sodipodi:r1="5.1116104"
|
||||||
|
sodipodi:cy="60.073212"
|
||||||
|
sodipodi:cx="11.55581"
|
||||||
|
sodipodi:sides="3"
|
||||||
|
id="path4504"
|
||||||
|
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
sodipodi:type="star"
|
||||||
|
transform="matrix(0,1,-1,0,72.0074,71.7877)"
|
||||||
|
inkscape:transform-center-y="1.2779029" />
|
||||||
|
<path
|
||||||
|
inkscape:transform-center-y="-1.2779026"
|
||||||
|
transform="matrix(0,-1,-1,0,96,96)"
|
||||||
|
sodipodi:type="star"
|
||||||
|
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
id="path4506"
|
||||||
|
sodipodi:sides="3"
|
||||||
|
sodipodi:cx="11.55581"
|
||||||
|
sodipodi:cy="60.073212"
|
||||||
|
sodipodi:r1="5.1116104"
|
||||||
|
sodipodi:r2="2.5558052"
|
||||||
|
sodipodi:arg1="0"
|
||||||
|
sodipodi:arg2="1.0471976"
|
||||||
|
inkscape:flatsided="false"
|
||||||
|
inkscape:rounded="0"
|
||||||
|
inkscape:randomized="0"
|
||||||
|
d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4615-5"
|
||||||
|
d="m 171.82574,65.174193 16.34854,0 -8.17427,-13.348454 z"
|
||||||
|
style="fill:#fbb917;fill-opacity:1;fill-rule:evenodd;stroke:#fbb917;stroke-width:1.65161395;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 179,55 0,6 2,0 0,-6"
|
||||||
|
id="path4300"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 179,62 0,2 2,0 0,-2"
|
||||||
|
id="path4300-6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 35 KiB |
2
public/css/jquery.datetimepicker.min.css
vendored
Normal file
1
public/css/jquery.datetimepicker.min.css.map
Normal file
1
public/css/jsoneditor.min.css.map
Normal file
2
public/css/lightbox.min.css
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
body:after{content:url(../images/close.png) url(../images/loading.gif) url(../images/prev.png) url(../images/next.png);display:none}body.lb-disable-scrolling{overflow:hidden}.lightboxOverlay{position:absolute;top:0;left:0;z-index:9999;background-color:#000;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);opacity:.8;display:none}.lightbox{position:absolute;left:0;width:100%;z-index:10000;text-align:center;line-height:0;font-weight:400}.lightbox .lb-image{display:block;height:auto;max-width:inherit;border-radius:3px}.lightbox a img{border:none}.lb-outerContainer{position:relative;background-color:#fff;*zoom:1;width:250px;height:250px;margin:0 auto;border-radius:4px}.lb-outerContainer:after{content:"";display:table;clear:both}.lb-container{padding:4px}.lb-loader{position:absolute;top:43%;left:0;height:25%;width:100%;text-align:center;line-height:0}.lb-cancel{display:block;width:32px;height:32px;margin:0 auto;background:url(../images/loading.gif) no-repeat}.lb-nav{position:absolute;top:0;left:0;height:100%;width:100%;z-index:10}.lb-container>.nav{left:0}.lb-nav a{outline:none;background-image:url('data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==')}.lb-next,.lb-prev{height:100%;cursor:pointer;display:block}.lb-nav a.lb-prev{width:34%;left:0;float:left;background:url(../images/prev.png) left 48% no-repeat;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);opacity:0;-webkit-transition:opacity .6s;transition:opacity .6s}.lb-nav a.lb-prev:hover{filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);opacity:1}.lb-nav a.lb-next{width:64%;right:0;float:right;background:url(../images/next.png) right 48% no-repeat;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);opacity:0;-webkit-transition:opacity .6s;transition:opacity .6s}.lb-nav a.lb-next:hover{filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);opacity:1}.lb-dataContainer{margin:0 auto;padding-top:5px;*zoom:1;width:100%;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.lb-dataContainer:after{content:"";display:table;clear:both}.lb-data{padding:0 4px;color:#ccc}.lb-data .lb-details{width:85%;float:left;text-align:left;line-height:1.1em}.lb-data .lb-caption{font-size:13px;font-weight:700;line-height:1em}.lb-data .lb-number{display:block;clear:left;padding-bottom:1em;font-size:12px;color:#999}.lb-data .lb-close{display:block;float:right;width:30px;height:30px;background:url(../images/close.png) 100% 0 no-repeat;text-align:right;outline:none;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=70);opacity:.7;-webkit-transition:opacity .2s;transition:opacity .2s}.lb-data .lb-close:hover{cursor:pointer;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);opacity:1}
|
||||||
|
/*# sourceMappingURL=lightbox.min.css.map */
|
1
public/css/lightbox.min.css.map
Normal file
6
public/css/quill.snow.min.css
vendored
Normal file
1
public/css/quill.snow.min.css.map
Normal file
2
public/css/style.min.css
vendored
Normal file
1
public/css/style.min.css.map
Normal file
BIN
public/favicon-16x16.png
Normal file
After Width: | Height: | Size: 939 B |
BIN
public/favicon-32x32.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 15 KiB |
BIN
public/images/close.png
Normal file
After Width: | Height: | Size: 280 B |
BIN
public/images/loading.gif
Normal file
After Width: | Height: | Size: 8.3 KiB |