Compare commits
183 Commits
2.1.21
...
74b15add36
Author | SHA1 | Date | |
---|---|---|---|
74b15add36 | |||
d8d2cba308 | |||
5983a4b20f | |||
6e4dd8180e | |||
7447579ef0 | |||
ccd5b296f3 | |||
095c33e8aa | |||
4604a9af48 | |||
55d879274c | |||
85b529c22d | |||
3ba45c48f5 | |||
552a4c7aca | |||
2070987403 | |||
d9dab9c88d | |||
f9f133d3a9 | |||
f85af642d2 | |||
f3d9b58ffb | |||
8f682f7f13 | |||
26e626074a | |||
478b407646 | |||
7d210601da | |||
9563876b36 | |||
d9e27d5af7 | |||
936830ae64 | |||
e93149456a | |||
93a15ef1e4 | |||
6950413eec | |||
9162ed240e | |||
84861b5e57 | |||
43bb7a83c8 | |||
081187e3d3 | |||
b2f1bd5ba0 | |||
a471a1083e | |||
8e7f43e487 | |||
390e79ad6d | |||
6169089475 | |||
a7ce78a3fb | |||
6f023928e8 | |||
a4b7183de1 | |||
a428aeebe1 | |||
fc543729d2 | |||
8cec046d66 | |||
1f730fb7f3 | |||
964d8d4237 | |||
0d5c9efd68 | |||
d68eba5697 | |||
d5b9be0196 | |||
d0d99eaa81 | |||
15e9a54c7e | |||
b7e9a17586 | |||
61533b5a4c | |||
5864e7ee94 | |||
3fc7aa88dc | |||
1caa62500a | |||
27e88761e0 | |||
b27a6fab33 | |||
fa978728ce | |||
256a3d2459 | |||
f8f5796a66 | |||
0e0b783a80 | |||
a5125aff74 | |||
71bbe7f2d7 | |||
e2c68a14d1 | |||
5e51562aec | |||
7719a5c614 | |||
05b9a3ad8a | |||
665bed8553 | |||
9c024d1ef7 | |||
94d618b2a1 | |||
4786ee2552 | |||
39d8d4943e | |||
e63a3d0077 | |||
d580cc1a11 | |||
86034a6349 | |||
97ab5acf3e | |||
435180ebaf | |||
d2511901ec | |||
9388dc17fc | |||
a33dd341cd | |||
8e4b5eaaf8 | |||
91679b164f | |||
3c7e4b9ef4 | |||
20045c9a64 | |||
47d43f504d | |||
0502b8e735 | |||
905e8263bc | |||
8710c8a111 | |||
5d9ac2bc51 | |||
062e0543e4 | |||
b97916cfc4 | |||
7af9cafdb6 | |||
84a2fbd119 | |||
bc9c71870c | |||
912e8624b2 | |||
86406bf027 | |||
7b8d44e8c8 | |||
c10f2e5912 | |||
bef0a22758 | |||
092eb95f06 | |||
5f56022109 | |||
4b3397dd63 | |||
529f9e32a1 | |||
939adf126f | |||
63400af1db | |||
019974614c | |||
735c341729 | |||
444ff687fc | |||
f3a5fa2cdc | |||
2ed265dcf1 | |||
dbae630fdd | |||
d69976d015 | |||
2ccbc31ae0 | |||
e50d80560c | |||
7cc0333876 | |||
eb38236926 | |||
85ef4dd60e | |||
f1e29e3b0b | |||
6617a92f5f | |||
ca958b8a88 | |||
dc2e2c7f71 | |||
936fd2d1e1 | |||
7c6a397e31 | |||
7385225a2e | |||
9c335fd350 | |||
57f9169cc7 | |||
8caa80459e | |||
98953cce42 | |||
c7dd309185 | |||
48bfe5d8ab | |||
d9b5bc6507 | |||
21d1ef653f | |||
e8d43e43ff | |||
fc9788a1cd | |||
02dcc950f4 | |||
370b6714bc | |||
dc7a9f9e7a | |||
cfe18c1909 | |||
5156858205 | |||
415ba31270 | |||
c784d1bee9 | |||
a1ade5c2c7 | |||
879b612493 | |||
b4cdd2d5f7 | |||
51cabee824 | |||
d2e51e76f8 | |||
1621d6fe30 | |||
0e32512adc | |||
338f290539 | |||
2aad7e1152 | |||
e542615128 | |||
1c7797b1b1 | |||
ba0d4073d7 | |||
faac3874a8 | |||
ade107ab3c | |||
c192cf1883 | |||
4fb75b11c4 | |||
ccbb71d875 | |||
7f25b4b5e1 | |||
f0b26a251b | |||
ea068d95d0 | |||
1ccc9ab3d4 | |||
5cd19bcdce | |||
712c70b34d | |||
35ab7e7e8b | |||
4b39f93f30 | |||
d3f188684a | |||
82647a171d | |||
e44ab30665 | |||
19333bc338 | |||
4738dae7c8 | |||
a370ffff43 | |||
88f9e539f7 | |||
671b26f038 | |||
e133bd36cf | |||
251dbbe0f0 | |||
e1eb2c4c56 | |||
1078f4c188 | |||
38962cb9cf | |||
3cd699d2e2 | |||
d8b8787be9 | |||
62edca5335 | |||
ac6c5b7d3d | |||
5b5a0ed1f5 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,3 +9,6 @@
|
||||
**/modules/
|
||||
**/.idea/
|
||||
**/upload?/
|
||||
**/informe?/
|
||||
**/.phpunit.cache/
|
||||
**/coverage/
|
||||
|
@ -1,16 +1,19 @@
|
||||
FROM php:8.2-fpm
|
||||
FROM php:8.2-cli
|
||||
|
||||
ENV TZ "America/Santiago"
|
||||
ENV TZ "${TZ}"
|
||||
ENV APP_NAME "${APP_NAME}"
|
||||
ENV API_URL "${API_URL}"
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends cron && rm -r /var/lib/apt/lists/*
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends cron rsyslog nano && rm -r /var/lib/apt/lists/*
|
||||
|
||||
RUN pecl install xdebug-3.2.2 \
|
||||
&& docker-php-ext-enable xdebug
|
||||
&& docker-php-ext-enable xdebug \
|
||||
&& echo "#/bin/bash\nprintenv >> /etc/environment\ncron -f -L 11" > /root/entrypoint && chmod a+x /root/entrypoint
|
||||
|
||||
COPY ./php-errors.ini /usr/local/etc/php/conf.d/docker-php-errors.ini
|
||||
|
||||
WORKDIR /code/bin
|
||||
|
||||
COPY ./cli/crontab /var/spool/cron/crontabs/root
|
||||
COPY --chmod=644 ./cli/crontab /var/spool/cron/crontabs/root
|
||||
|
||||
CMD ["cron", "-f"]
|
||||
CMD [ "/root/entrypoint" ]
|
||||
|
@ -9,6 +9,8 @@ RUN pecl install xdebug-3.1.3 \
|
||||
&& docker-php-ext-enable xdebug
|
||||
|
||||
COPY ./php-errors.ini /usr/local/etc/php/conf.d/docker-php-errors.ini
|
||||
COPY ./php-xdebug.ini /usr/local/etc/php/conf.d/docker-php-xdebug.ini
|
||||
COPY ./php-memory.ini /usr/local/etc/php/conf.d/docker-php-memory.ini
|
||||
|
||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||
|
||||
|
9
api.compose.yml
Normal file
9
api.compose.yml
Normal file
@ -0,0 +1,9 @@
|
||||
services:
|
||||
httpclient:
|
||||
profiles:
|
||||
- testing
|
||||
container_name: incoviba_client
|
||||
image: flawiddsouza/restfox
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${HTTPCLIENT_PORT:-4004}:4004"
|
1
app/.gitignore
vendored
Normal file
1
app/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
**/bin
|
13
app/.phpunit-watcher.yml
Normal file
13
app/.phpunit-watcher.yml
Normal file
@ -0,0 +1,13 @@
|
||||
watch:
|
||||
directories:
|
||||
- src
|
||||
- tests
|
||||
- common
|
||||
fileMask: '*.php'
|
||||
notifications:
|
||||
passingTests: false
|
||||
failingTests: false
|
||||
hideManual: true
|
||||
phpunit:
|
||||
arguments: '--log-events-text /logs/output.txt --stop-on-failure'
|
||||
timeout: 180
|
@ -5,6 +5,11 @@ use Psr\Http\Message\UploadedFileInterface;
|
||||
|
||||
interface Banco
|
||||
{
|
||||
/**
|
||||
* Process bank movements for database inserts
|
||||
* @param UploadedFileInterface $file
|
||||
* @return array
|
||||
*/
|
||||
public function process(UploadedFileInterface $file): array;
|
||||
|
||||
}
|
||||
|
@ -6,5 +6,5 @@ use Incoviba\Model;
|
||||
|
||||
interface Exporter
|
||||
{
|
||||
public function export(Model\Inmobiliaria $inmobiliaria, Model\Banco $banco, DateTimeInterface $mes, array $movimientos): string;
|
||||
public function export(Model\Inmobiliaria $inmobiliaria, Model\Contabilidad\Banco $banco, DateTimeInterface $mes, array $movimientos): string;
|
||||
}
|
||||
|
10
app/common/Define/Informe.php
Normal file
10
app/common/Define/Informe.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace Incoviba\Common\Define;
|
||||
|
||||
interface Informe
|
||||
{
|
||||
public function setTitle(string $title): Informe;
|
||||
public function setFilename(string $filename): Informe;
|
||||
public function addData(array $rows): Informe;
|
||||
public function build(): void;
|
||||
}
|
@ -2,18 +2,68 @@
|
||||
namespace Incoviba\Common\Ideal\Cartola;
|
||||
|
||||
use Incoviba\Common\Define;
|
||||
use Incoviba\Common\Ideal\Service;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
|
||||
abstract class Banco implements Define\Cartola\Banco
|
||||
abstract class Banco extends Service implements Define\Cartola\Banco
|
||||
{
|
||||
public function process(UploadedFileInterface $file): array
|
||||
{
|
||||
$data = $this->parseFile($file);
|
||||
$filename = $this->processUploadedFile($file);
|
||||
$data = $this->processFile($filename);
|
||||
return $this->mapColumns($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* There are banks that need some post-processing
|
||||
* @param array $movimientos
|
||||
* @return array
|
||||
*/
|
||||
public function processMovimientosDiarios(array $movimientos): array
|
||||
{
|
||||
return $movimientos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the UploadedFile into a temp file from getFilename
|
||||
* @param UploadedFileInterface $uploadedFile
|
||||
* @return string
|
||||
*/
|
||||
protected function processUploadedFile(UploadedFileInterface $uploadedFile): string
|
||||
{
|
||||
$filename = $this->getFilename($uploadedFile);
|
||||
$uploadedFile->moveTo($filename);
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the temp file from getFilename and remove it
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
protected function processFile(string $filename): array
|
||||
{
|
||||
$data = $this->parseFile($filename);
|
||||
unlink($filename);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map columns from uploaded file data to database columns
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function mapColumns(array $data): array
|
||||
{
|
||||
$temp = [];
|
||||
$columns = $this->columnMap();
|
||||
|
||||
foreach ($data as $row) {
|
||||
$r = [];
|
||||
foreach ($columns as $old => $new) {
|
||||
if (!isset($row[$old])) {
|
||||
continue;
|
||||
}
|
||||
$r[$new] = $row[$old];
|
||||
}
|
||||
$temp []= $r;
|
||||
@ -21,6 +71,23 @@ abstract class Banco implements Define\Cartola\Banco
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename where to move UploadedFile
|
||||
* @param UploadedFileInterface $uploadedFile
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getFilename(UploadedFileInterface $uploadedFile): string;
|
||||
|
||||
/**
|
||||
* Mapping of uploaded file data columns to database columns
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function columnMap(): array;
|
||||
abstract protected function parseFile(UploadedFileInterface $uploadedFile): array;
|
||||
|
||||
/**
|
||||
* Translate uploaded file data to database data
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function parseFile(string $filename): array;
|
||||
}
|
||||
|
@ -37,6 +37,9 @@ abstract class Repository implements Define\Repository
|
||||
$this->connection->execute($query, [$model->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws EmptyResult
|
||||
*/
|
||||
public function fetchById(int $id): Define\Model
|
||||
{
|
||||
$query = $this->connection->getQueryBuilder()
|
||||
@ -45,6 +48,10 @@ abstract class Repository implements Define\Repository
|
||||
->where("{$this->getKey()} = ?");
|
||||
return $this->fetchOne($query, [$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws EmptyResult
|
||||
*/
|
||||
public function fetchAll(null|string|array $ordering = null): array
|
||||
{
|
||||
$query = $this->connection->getQueryBuilder()
|
||||
@ -161,4 +168,9 @@ abstract class Repository implements Define\Repository
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
public function filterData(array $data): array
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use Throwable;
|
||||
|
||||
class EmptyResult extends Exception
|
||||
{
|
||||
public function __construct(string $query, ?Throwable $previous = null)
|
||||
public function __construct(public string $query, ?Throwable $previous = null)
|
||||
{
|
||||
$message = "Empty results for {$query}";
|
||||
$code = 700;
|
||||
|
19
app/common/Implement/Exception/HttpResponse.php
Normal file
19
app/common/Implement/Exception/HttpResponse.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace Incoviba\Common\Implement\Exception;
|
||||
|
||||
use Throwable;
|
||||
use Exception;
|
||||
|
||||
class HttpResponse extends Exception
|
||||
{
|
||||
public function __construct($reason = "", $message = "", $code = 0, Throwable $previous = null)
|
||||
{
|
||||
$this->reason = "HTTP Reason: {$reason}";
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
protected string $reason;
|
||||
public function getReason(): string
|
||||
{
|
||||
return $this->reason;
|
||||
}
|
||||
}
|
60
app/common/Implement/Log/MySQLHandler.php
Normal file
60
app/common/Implement/Log/MySQLHandler.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Incoviba\Common\Implement\Log;
|
||||
|
||||
use PDOStatement;
|
||||
use Monolog\Handler\AbstractProcessingHandler;
|
||||
use Monolog\LogRecord;
|
||||
use Monolog\Level;
|
||||
use Incoviba\Common\Define\Connection;
|
||||
|
||||
class MySQLHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private bool $initialized = false;
|
||||
private PDOStatement $statement;
|
||||
|
||||
public function __construct(protected Connection $connection, protected int $retainDays = 90, int|string|Level $level = Level::Debug, bool $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
public function write(LogRecord $record): void
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initialized();
|
||||
}
|
||||
$this->cleanup();
|
||||
$this->statement->execute([
|
||||
'channel' => $record->channel,
|
||||
'level' => $record->level->getName(),
|
||||
'message' => $record->formatted,
|
||||
'time' => $record->datetime->format('Y-m-d H:i:s.u'),
|
||||
'context' => (count($record->context) > 0) ? json_encode($record->context, JSON_UNESCAPED_SLASHES) : '',
|
||||
'extra' => (count($record->extra) > 0) ? json_encode($record->extra, JSON_UNESCAPED_SLASHES) : ''
|
||||
]);
|
||||
}
|
||||
|
||||
private function initialized(): void
|
||||
{
|
||||
$query = <<<QUERY
|
||||
CREATE TABLE IF NOT EXISTS monolog (
|
||||
channel VARCHAR(255),
|
||||
level VARCHAR(100),
|
||||
message LONGTEXT,
|
||||
time DATETIME,
|
||||
context LONGTEXT,
|
||||
extra LONGTEXT
|
||||
)
|
||||
QUERY;
|
||||
$this->connection->getPDO()->exec($query);
|
||||
$query = <<<QUERY
|
||||
INSERT INTO monolog (channel, level, message, time, context, extra)
|
||||
VALUES (:channel, :level, :message, :time, :context, :extra)
|
||||
QUERY;
|
||||
$this->statement = $this->connection->getPDO()->prepare($query);
|
||||
$this->initialized = true;
|
||||
}
|
||||
private function cleanup(): void
|
||||
{
|
||||
$query = "DELETE FROM monolog WHERE time < DATE_SUB(CURDATE(), INTERVAL {$this->retainDays} DAY)";
|
||||
$this->connection->query($query);
|
||||
}
|
||||
}
|
19
app/common/Implement/Log/PDOFormatter.php
Normal file
19
app/common/Implement/Log/PDOFormatter.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace Incoviba\Common\Implement\Log;
|
||||
|
||||
use Monolog\Formatter\JsonFormatter;
|
||||
use Monolog\LogRecord;
|
||||
|
||||
class PDOFormatter extends JsonFormatter
|
||||
{
|
||||
public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $appendNewline = false, bool $ignoreEmptyContextAndExtra = false, bool $includeStacktraces = true)
|
||||
{
|
||||
parent::__construct($batchMode, $appendNewline, $ignoreEmptyContextAndExtra, $includeStacktraces);
|
||||
}
|
||||
|
||||
public function format(LogRecord $record): string
|
||||
{
|
||||
$normalized = $this->normalize($record);
|
||||
return $normalized['message'];
|
||||
}
|
||||
}
|
18
app/common/Implement/Log/UserProcessor.php
Normal file
18
app/common/Implement/Log/UserProcessor.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
namespace Incoviba\Common\Implement\Log;
|
||||
|
||||
use Monolog\LogRecord;
|
||||
use Monolog\Processor\ProcessorInterface;
|
||||
use Incoviba\Service;
|
||||
|
||||
class UserProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(protected Service\Login $loginService) {}
|
||||
public function __invoke(LogRecord $record): LogRecord
|
||||
{
|
||||
if ($this->loginService->isIn()) {
|
||||
$record->extra['user'] = $this->loginService->getUser()->name;
|
||||
}
|
||||
return $record;
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
<?php
|
||||
namespace Incoviba\Common\Implement\Repository;
|
||||
|
||||
use Error;
|
||||
use Closure;
|
||||
use Incoviba\Common\Define;
|
||||
use Incoviba\Common\Implement\Exception\EmptyResult;
|
||||
|
||||
class Mapper implements Define\Repository\Mapper
|
||||
{
|
||||
@ -46,7 +48,11 @@ class Mapper implements Define\Repository\Mapper
|
||||
}
|
||||
public function hasDefault(): bool
|
||||
{
|
||||
return isset($this->default);
|
||||
try {
|
||||
return isset($this->default) or $this->default === null;
|
||||
} catch (Error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function parse(Define\Model &$model, string $column, ?array $data): bool
|
||||
@ -63,7 +69,15 @@ class Mapper implements Define\Repository\Mapper
|
||||
$value = $data[$column];
|
||||
if ($this->hasFunction()) {
|
||||
if ($value !== null) {
|
||||
try {
|
||||
$value = ($this->function)($data);
|
||||
} catch (EmptyResult $exception) {
|
||||
if ($this->hasDefault()) {
|
||||
$value = $this->default;
|
||||
} else {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
} elseif ($this->hasDefault()) {
|
||||
$value = $this->default;
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
{
|
||||
"name": "incoviba/web",
|
||||
"version": "2.0.0",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"berrnd/slim-blade-view": "^1.0",
|
||||
"ext-gd": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-pdo": "*",
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"monolog/monolog": "^3.4",
|
||||
"nyholm/psr7": "^1.8",
|
||||
@ -14,8 +18,10 @@
|
||||
"slim/slim": "^4.11"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
"kint-php/kint": "^5.1",
|
||||
"phpunit/phpunit": "^10.2"
|
||||
"phpunit/phpunit": "^10.2",
|
||||
"spatie/phpunit-watcher": "^1.23"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
@ -30,6 +36,8 @@
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
"sort-packages": true,
|
||||
"process-timeout": 0,
|
||||
"bin-dir": "bin"
|
||||
}
|
||||
}
|
||||
|
43
app/phpunit.xml
Normal file
43
app/phpunit.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
cacheDirectory="/code/cache/tests"
|
||||
executionOrder="depends,defects"
|
||||
requireCoverageMetadata="false"
|
||||
beStrictAboutCoverageMetadata="false"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
colors="true"
|
||||
failOnRisky="false"
|
||||
failOnWarning="false">
|
||||
<testsuites>
|
||||
<testsuite name="unit">
|
||||
<directory>tests/units</directory>
|
||||
</testsuite>
|
||||
<testsuite name="acceptance">
|
||||
<directory>tests/integration</directory>
|
||||
</testsuite>
|
||||
<testsuite name="performance">
|
||||
<directory>tests/performance</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<source restrictDeprecations="true" restrictNotices="true" restrictWarnings="true">
|
||||
<include>
|
||||
<directory>src</directory>
|
||||
<directory>common</directory>
|
||||
</include>
|
||||
</source>
|
||||
<coverage includeUncoveredFiles="true" pathCoverage="false" ignoreDeprecatedCodeUnits="true" disableCodeCoverageIgnore="true">
|
||||
<report>
|
||||
<html outputDirectory="/code/public/coverage/html" />
|
||||
<php outputFile="/code/public/coverage/coverage.php" />
|
||||
</report>
|
||||
</coverage>
|
||||
<logging>
|
||||
<junit outputFile="/code/cache/tests/junit.xml" />
|
||||
<teamcity outputFile="/code/cache/tests/teamcity.txt" />
|
||||
<testdoxHtml outputFile="/code/cache/tests/testdox.html" />
|
||||
<testdoxText outputFile="/code/cache/tests/testdox.txt" />
|
||||
</logging>
|
||||
</phpunit>
|
BIN
app/public/favicon.ico
Normal file
BIN
app/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 894 B |
0
app/public/informes/.gitkeep
Normal file
0
app/public/informes/.gitkeep
Normal file
@ -1,4 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Base;
|
||||
|
||||
$app->group('/api', function($app) {
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'api']);
|
||||
if (file_exists($folder)) {
|
||||
@ -10,4 +12,5 @@ $app->group('/api', function($app) {
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
}
|
||||
$app->get('[/]', Base::class);
|
||||
})->add($app->getContainer()->get(Incoviba\Middleware\API::class));
|
||||
|
@ -2,5 +2,15 @@
|
||||
use Incoviba\Controller\Inmobiliarias;
|
||||
|
||||
$app->group('/inmobiliarias', function($app) {
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'inmobiliarias']);
|
||||
if (file_exists($folder)) {
|
||||
$files = new FilesystemIterator($folder);
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
}
|
||||
$app->get('[/]', Inmobiliarias::class);
|
||||
})->add($app->getContainer()->get(Incoviba\Middleware\Authentication::class));
|
||||
|
@ -28,6 +28,12 @@ $app->group('/venta/{venta_id:[0-9]+}', function($app) {
|
||||
});
|
||||
$app->get('[/]', [Ventas::class, 'pie']);
|
||||
});
|
||||
$app->group('/escritura', function($app) {
|
||||
$app->get('/add[/]', [Ventas\Escrituras::class, 'add']);
|
||||
});
|
||||
$app->group('/credito', function($app) {
|
||||
$app->get('[/]', [Ventas\Creditos::class, 'show']);
|
||||
});
|
||||
$app->get('/escriturar[/]', [Ventas::class, 'escriturar']);
|
||||
$app->get('/desistir[/]', [Ventas::class, 'desistir']);
|
||||
$app->get('/desistida[/]', [Ventas::class, 'desistida']);
|
||||
|
10
app/resources/routes/96_admin.php
Normal file
10
app/resources/routes/96_admin.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
$app->group('/admin', function($app) {
|
||||
$files = new FilesystemIterator(implode(DIRECTORY_SEPARATOR, [__DIR__, 'admin']));
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
});
|
6
app/resources/routes/admin/users.php
Normal file
6
app/resources/routes/admin/users.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\Admin\Users;
|
||||
|
||||
$app->group('/users', function($app) {
|
||||
$app->get('[/]', Users::class);
|
||||
});
|
13
app/resources/routes/api/admin.php
Normal file
13
app/resources/routes/api/admin.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
$app->group('/admin', function($app) {
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'admin']);
|
||||
if (file_exists($folder)) {
|
||||
$files = new FilesystemIterator($folder);
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
}
|
||||
});
|
6
app/resources/routes/api/admin/users.php
Normal file
6
app/resources/routes/api/admin/users.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Admin\Users;
|
||||
|
||||
$app->group('/users', function($app) {
|
||||
$app->post('/add[/]', Users::class . ':add');
|
||||
});
|
@ -1,9 +1,15 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Contabilidad;
|
||||
use Incoviba\Controller\API\Contabilidad\Cartolas;
|
||||
|
||||
$app->group('/cartolas', function($app) {
|
||||
$app->post('/procesar[/]', [Contabilidad::class, 'procesarCartola']);
|
||||
$app->post('/procesar[/]', [Cartolas::class, 'procesar']);
|
||||
$app->post('/importar[/]', [Cartolas::class, 'importar']);
|
||||
$app->get('/update[/]', [Cartolas::class, 'update']);
|
||||
});
|
||||
$app->group('/cartola', function($app) {
|
||||
$app->post('/exportar[/]', [Contabilidad::class, 'exportarCartola']);
|
||||
$app->group('/diaria', function($app) {
|
||||
$app->post('/ayer[/]', [Cartolas::class, 'ayer']);
|
||||
$app->post('/procesar[/]', [Cartolas::class, 'diaria']);
|
||||
});
|
||||
$app->post('/exportar[/]', [Cartolas::class, 'exportar']);
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\CentrosCostos;
|
||||
|
||||
use Incoviba\Controller\API\Contabilidad\CentrosCostos;
|
||||
|
||||
$app->group('/centros_costos', function($app) {
|
||||
$app->post('/add[/]', [CentrosCostos::class, 'add']);
|
||||
|
7
app/resources/routes/api/contabilidad/daps.php
Normal file
7
app/resources/routes/api/contabilidad/daps.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Contabilidad\Depositos;
|
||||
|
||||
$app->group('/depositos', function($app) {
|
||||
$app->post('/add[/]', [Depositos::class, 'add']);
|
||||
$app->get('/inmobiliaria/{inmobiliaria_rut}[/]', [Depositos::class, 'inmobiliaria']);
|
||||
});
|
11
app/resources/routes/api/contabilidad/movimientos.php
Normal file
11
app/resources/routes/api/contabilidad/movimientos.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Contabilidad\Movimientos;
|
||||
|
||||
$app->group('/movimientos', function($app) {
|
||||
$app->post('/sociedad/mes', [Movimientos::class, 'sociedad']);
|
||||
$app->post('/segment', [Movimientos::class, 'segment']);
|
||||
$app->get('[/]', Movimientos::class);
|
||||
});
|
||||
$app->group('/movimiento/{movimiento_id}', function($app) {
|
||||
$app->post('/detalles', [Movimientos::class, 'detalles']);
|
||||
});
|
@ -1,11 +1,14 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Nubox;
|
||||
use Incoviba\Controller\API\Contabilidad\Nubox;
|
||||
|
||||
$app->group('/nubox/{inmobiliaria_rut}', function($app) {
|
||||
$app->get('/token[/]', [Nubox::class, 'token']);
|
||||
$app->get('/sistemas[/]', [Nubox::class, 'sistemas']);
|
||||
$app->get('/cuentas[/]', [Nubox::class, 'cuentas']);
|
||||
$app->group('/libro', function($app) {
|
||||
$app->post('/mayor[/]', [Nubox::class, 'libroMayor']);
|
||||
$app->post('/diario[/]', [Nubox::class, 'libroDiario']);
|
||||
});
|
||||
$app->get('/facturas/{dia}[/]', [Nubox::class, 'facturas']);
|
||||
$app->post('/cuenta', [Nubox::class, 'cuenta']);
|
||||
});
|
||||
|
6
app/resources/routes/api/contabilidad/tesoreria.php
Normal file
6
app/resources/routes/api/contabilidad/tesoreria.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Contabilidad\Tesoreria;
|
||||
|
||||
$app->group('/tesoreria', function($app) {
|
||||
$app->post('/import[/]', [Tesoreria::class, 'import']);
|
||||
});
|
@ -2,9 +2,20 @@
|
||||
use Incoviba\Controller\API\Inmobiliarias;
|
||||
|
||||
$app->group('/inmobiliarias', function($app) {
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'inmobiliarias']);
|
||||
if (file_exists($folder)) {
|
||||
$files = new FilesystemIterator($folder);
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
}
|
||||
$app->get('[/]', Inmobiliarias::class);
|
||||
});
|
||||
$app->group('/inmobiliaria/{inmobiliaria_rut}', function($app) {
|
||||
$app->post('/proveedores', [Inmobiliarias::class, 'proveedores']);
|
||||
$app->get('/cuentas[/]', [Inmobiliarias::class, 'cuentas']);
|
||||
$app->get('/proyectos[/]', [Inmobiliarias::class, 'proyectos']);
|
||||
});
|
||||
|
11
app/resources/routes/api/inmobiliarias/proveedores.php
Normal file
11
app/resources/routes/api/inmobiliarias/proveedores.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Inmobiliarias\Agentes;
|
||||
|
||||
$app->group('/proveedores', function($app) {
|
||||
$app->post('/add[/]', [Agentes::class, 'add']);
|
||||
$app->post('/register[/]', [Agentes::class, 'register']);
|
||||
$app->get('[/]', Agentes::class);
|
||||
});
|
||||
$app->group('/proveedor/{agente_id}', function($app) {
|
||||
$app->post('/edit[/]', [Agentes::class, 'edit']);
|
||||
});
|
7
app/resources/routes/api/inmobiliarias/sociedades.php
Normal file
7
app/resources/routes/api/inmobiliarias/sociedades.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Inmobiliarias\Sociedades;
|
||||
|
||||
$app->group('/sociedades', function($app) {
|
||||
$app->post('/add[/]', [Sociedades::class, 'add']);
|
||||
$app->get('[/]', Sociedades::class);
|
||||
});
|
4
app/resources/routes/api/login.php
Normal file
4
app/resources/routes/api/login.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Login;
|
||||
|
||||
$app->post('/login[/]', Login::class);
|
@ -4,5 +4,10 @@ use Incoviba\Controller\API\Money;
|
||||
$app->group('/money', function($app) {
|
||||
$app->post('/ipc[/]', [Money::class, 'ipc']);
|
||||
$app->post('/uf[/]', [Money::class, 'uf']);
|
||||
$app->group('/ufs', function($app) {
|
||||
$app->post('[/]', [Money::class, 'updateUfs']);
|
||||
$app->get('[/]', [Money::class, 'ufs']);
|
||||
});
|
||||
$app->post('/many[/]', [Money::class, 'getMany']);
|
||||
$app->post('[/]', [Money::class, 'get']);
|
||||
});
|
||||
|
@ -1,4 +1,12 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Search;
|
||||
|
||||
$app->post('/search', [Search::class, 'query']);
|
||||
$app->group('/search', function($app) {
|
||||
$app->group('/ventas', function($app) {
|
||||
$app->post('/unidades', [Search::class, 'unidades']);
|
||||
$app->get('/unidad/{unidad_id}', [Search::class, 'unidad']);
|
||||
$app->post('[/]', [Search::class, 'ventas']);
|
||||
});
|
||||
$app->get('/venta/{venta_id}', [Search::class, 'venta']);
|
||||
$app->post('[/]', [Search::class, 'query']);
|
||||
});
|
||||
|
17
app/resources/routes/api/sociedades.php
Normal file
17
app/resources/routes/api/sociedades.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Sociedades;
|
||||
|
||||
$app->group('/sociedades', function($app) {
|
||||
$app->group('/add', function($app) {
|
||||
$app->post('/one[/]', Sociedades::class . ':add');
|
||||
$app->post('[/]', Sociedades::class . ':addMany');
|
||||
});
|
||||
$app->post('/get[/]', [Sociedades::class, 'getMany']);
|
||||
$app->post('/edit[/]', [Sociedades::class, 'edit']);
|
||||
$app->post('/delete[/]', [Sociedades::class, 'delete']);
|
||||
$app->post('/asisgnar[/]', [Sociedades::class, 'asignar']);
|
||||
$app->get('[/]', Sociedades::class);
|
||||
});
|
||||
$app->group('/sociedad/{sociedad_rut}', function($app) {
|
||||
$app->get('[/]', Sociedades::class . ':get');
|
||||
});
|
6
app/resources/routes/api/tokens.php
Normal file
6
app/resources/routes/api/tokens.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Tokens;
|
||||
|
||||
$app->group('/tokens', function($app) {
|
||||
$app->get('/try[/]', Tokens::class . ':try');
|
||||
});
|
@ -19,16 +19,32 @@ $app->group('/ventas', function($app) {
|
||||
$app->group('/escrituras', function($app) {
|
||||
$app->post('/estados[/]', [Ventas::class, 'escrituras']);
|
||||
});
|
||||
$app->group('/by', function($app) {
|
||||
$app->get('/unidad/{unidad_id}', [Ventas::class, 'unidad']);
|
||||
});
|
||||
$app->post('/get[/]', [Ventas::class, 'getMany']);
|
||||
$app->post('[/]', [Ventas::class, 'proyecto']);
|
||||
});
|
||||
$app->group('/venta/{venta_id}', function($app) {
|
||||
$app->get('/unidades[/]', [Ventas::class, 'unidades']);
|
||||
$app->get('/comentarios[/]', [Ventas::class, 'comentarios']);
|
||||
$app->group('/comentarios', function($app) {
|
||||
$app->post('/add[/]', [Ventas::class, 'addComentario']);
|
||||
$app->get('[/]', [Ventas::class, 'comentarios']);
|
||||
});
|
||||
$app->group('/escritura', function($app) {
|
||||
$app->post('/add[/]', [Ventas\Escrituras::class, 'add']);
|
||||
});
|
||||
$app->group('/credito', function($app) {
|
||||
$app->post('[/]', [Ventas\Creditos::class, 'edit']);
|
||||
});
|
||||
$app->post('/escriturar[/]', [Ventas::class, 'escriturar']);
|
||||
$app->group('/desistir', function($app) {
|
||||
$app->get('/eliminar[/]', [Ventas::class, 'insistir']);
|
||||
$app->post('[/]', [Ventas::class, 'desistir']);
|
||||
});
|
||||
$app->group('/propietario', function($app) {
|
||||
$app->put('/edit[/]', [Ventas::class, 'propietario']);
|
||||
});
|
||||
$app->post('[/]', [Ventas::class, 'edit']);
|
||||
$app->get('[/]', [Ventas::class, 'get']);
|
||||
});
|
||||
|
8
app/resources/routes/api/ventas/comentarios.php
Normal file
8
app/resources/routes/api/ventas/comentarios.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Ventas\Comentarios;
|
||||
|
||||
$app->group('/comentario/{comentario_id}', function($app) {
|
||||
$app->post('/edit[/]', [Comentarios::class, 'edit']);
|
||||
$app->delete('/remove[/]', [Comentarios::class, 'remove']);
|
||||
//$app->get('[/]', [Comentarios::class, 'get']);
|
||||
});
|
@ -3,4 +3,5 @@ use Incoviba\Controller\API\Ventas\Facturacion;
|
||||
|
||||
$app->group('/facturacion', function($app) {
|
||||
$app->get('/proyecto/{proyecto_id}[/]', [Facturacion::class, 'proyecto']);
|
||||
$app->post('/get[/]', [Facturacion::class, 'ventas']);
|
||||
});
|
||||
|
6
app/resources/routes/api/ventas/facturas.php
Normal file
6
app/resources/routes/api/ventas/facturas.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\API\Ventas\Facturas;
|
||||
|
||||
$app->group('/facturas', function($app) {
|
||||
$app->post('/add[/]', [Facturas::class, 'add']);
|
||||
});
|
7
app/resources/routes/contabilidad/cartolas.php
Normal file
7
app/resources/routes/contabilidad/cartolas.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
use Incoviba\Controller\Contabilidad;
|
||||
|
||||
$app->group('/cartolas', function($app) {
|
||||
$app->get('/diaria[/]', [Contabilidad::class, 'diaria']);
|
||||
$app->get('/importar[/]', [Contabilidad::class, 'importar']);
|
||||
});
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\CentrosCostos;
|
||||
|
||||
use Incoviba\Controller\Contabilidad\CentrosCostos;
|
||||
|
||||
$app->group('/centros_costos', function($app) {
|
||||
$app->get('/asignar[/]', [CentrosCostos::class, 'asignar']);
|
||||
|
4
app/resources/routes/contabilidad/cuadratura.php
Normal file
4
app/resources/routes/contabilidad/cuadratura.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Incoviba\Controller\Contabilidad;
|
||||
|
||||
$app->get('/cuadratura[/]', [Contabilidad::class, 'cuadratura']);
|
6
app/resources/routes/contabilidad/daps.php
Normal file
6
app/resources/routes/contabilidad/daps.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\Contabilidad;
|
||||
|
||||
$app->group('/depositos', function($app) {
|
||||
$app->get('[/]', [Contabilidad::class, 'depositos']);
|
||||
});
|
10
app/resources/routes/contabilidad/informes.php
Normal file
10
app/resources/routes/contabilidad/informes.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
$app->group('/informes', function($app) {
|
||||
$files = new FilesystemIterator(implode(DIRECTORY_SEPARATOR, [__DIR__, 'informes']));
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
});
|
8
app/resources/routes/contabilidad/informes/tesoreria.php
Normal file
8
app/resources/routes/contabilidad/informes/tesoreria.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
use Incoviba\Controller\Contabilidad;
|
||||
use Incoviba\Controller\Contabilidad\Tesoreria;
|
||||
|
||||
$app->group('/tesoreria', function($app) {
|
||||
$app->get('/import[/]', [Tesoreria::class, 'import']);
|
||||
$app->get('[/[{fecha}[/]]]', [Contabilidad::class, 'tesoreria']);
|
||||
});
|
6
app/resources/routes/contabilidad/informes/xlsx.php
Normal file
6
app/resources/routes/contabilidad/informes/xlsx.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\Contabilidad\Informes;
|
||||
|
||||
$app->group('/xlsx', function($app) {
|
||||
$app->get('/tesoreria/{fecha}[/]', [Informes::class, 'tesoreria']);
|
||||
});
|
4
app/resources/routes/contabilidad/movimientos.php
Normal file
4
app/resources/routes/contabilidad/movimientos.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Incoviba\Controller\Contabilidad\Movimientos;
|
||||
|
||||
$app->get('/movimientos', Movimientos::class);
|
6
app/resources/routes/inmobiliarias/proveedores.php
Normal file
6
app/resources/routes/inmobiliarias/proveedores.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use Incoviba\Controller\Inmobiliarias\Proveedores;
|
||||
|
||||
$app->group('/proveedores', function($app) {
|
||||
$app->get('[/]', Proveedores::class);
|
||||
});
|
100
app/resources/views/admin/users.blade.php
Normal file
100
app/resources/views/admin/users.blade.php
Normal file
@ -0,0 +1,100 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_content')
|
||||
<div class="ui container">
|
||||
<h2 class="ui header">Usuarios</h2>
|
||||
<table class="ui table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th class="right aligned">
|
||||
<button class="ui mini green icon button" id="create-user-button">
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($users as $user)
|
||||
<tr>
|
||||
<td>{{ $user->name }}</td>
|
||||
<td class="right aligned">
|
||||
<button class="ui mini blue icon button">
|
||||
<i class="edit icon"></i>
|
||||
</button>
|
||||
<button class="ui mini red icon button">
|
||||
<i class="trash icon"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="ui modal" id="create-user-modal">
|
||||
<i class="close icon"></i>
|
||||
<div class="header">
|
||||
Crear usuario
|
||||
</div>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<div class="field">
|
||||
<label>Nombre</label>
|
||||
<input type="text" name="name" placeholder="Nombre">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Correo</label>
|
||||
<input type="email" name="email" placeholder="Correo">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Contraseña</label>
|
||||
<input type="password" name="password" placeholder="Contraseña">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<div class="ui black deny button">
|
||||
Cancelar
|
||||
</div>
|
||||
<div class="ui positive right labeled icon button">
|
||||
Crear
|
||||
<i class="checkmark icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@include('layout.body.scripts.cryptojs')
|
||||
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
function encryptPassword(password) {
|
||||
const passphrase = Math.floor(Math.random() * Date.now()).toString()
|
||||
const encrypted = CryptoJS.AES.encrypt(password, passphrase)
|
||||
return [passphrase, encrypted.toString()].join('')
|
||||
}
|
||||
$(document).ready(function () {
|
||||
$('#create-user-modal').modal({
|
||||
onApprove: function() {
|
||||
const url = '{{$urls->api}}/admin/users/add'
|
||||
const method = 'post'
|
||||
const body = new FormData(document.querySelector('#create-user-modal form'))
|
||||
body.set('password', encryptPassword(body.get('password')))
|
||||
fetchAPI(url, {method, body}).then(response => {
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
response.json().then(result => {
|
||||
if (result.success) {
|
||||
location.reload()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
$('#create-user-button').on('click', function () {
|
||||
$('#create-user-modal').modal('show')
|
||||
})
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -10,5 +10,23 @@
|
||||
<i class="hammer icon"></i>
|
||||
Esta parte del sitio está en construcción.
|
||||
</div>
|
||||
@if (isset($exception))
|
||||
<div class="ui warning message">
|
||||
<i class="exclamation triangle icon"></i>
|
||||
<div class="content">
|
||||
<div class="header">Error</div>
|
||||
<p>{{$message}}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@if (isset($error))
|
||||
<div class="ui error message">
|
||||
<i class="exclamation triangle icon"></i>
|
||||
<div class="content">
|
||||
<div class="header">Error</div>
|
||||
<p>{{$message}}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
|
880
app/resources/views/contabilidad/cartolas/diaria.blade.php
Normal file
880
app/resources/views/contabilidad/cartolas/diaria.blade.php
Normal file
@ -0,0 +1,880 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_content')
|
||||
<div class="ui container">
|
||||
<h1 class="ui header">
|
||||
Cartola Diaria
|
||||
</h1>
|
||||
<div class="ui grid">
|
||||
<div class="right aligned sixteen wide column">
|
||||
<button class="ui green icon button" id="add_button">
|
||||
Agregar
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<form class="ui form" id="cartola_form">
|
||||
<input type="hidden" id="fields" name="fields" value="0" />
|
||||
</form>
|
||||
<div class="ui two columns grid">
|
||||
<div class="column">
|
||||
<button class="ui icon button" id="process_button">
|
||||
<i class="file excel icon"></i>
|
||||
Procesar
|
||||
</button>
|
||||
</div>
|
||||
<div class="right aligned column">
|
||||
<div class="ui inline active loader" id="loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
<table class="ui table" id="diferencia">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Sociedad</th>
|
||||
<th>Banco - Cuenta</th>
|
||||
<th>Hoy</th>
|
||||
<th>Último Saldo</th>
|
||||
<th>Saldo Actual</th>
|
||||
<th>Diferencia</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="ui fluid container">
|
||||
<table class="ui table" id="tabla_movimientos">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Sociedad</th>
|
||||
<th>Banco - Cuenta</th>
|
||||
<th>Fecha</th>
|
||||
<th>Glosa</th>
|
||||
<th class="right aligned">Cargo</th>
|
||||
<th class="right aligned">Abono</th>
|
||||
<th class="right aligned">Saldo</th>
|
||||
<th class="right aligned"></th>
|
||||
<th>Orden</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="movimientos"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="ui modal" id="manual_modal">
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
Movimientos |
|
||||
<span id="modal_inmobiliaria"></span> |
|
||||
<span id="modal_cuenta"></span> |
|
||||
<span id="modal_fecha"></span>
|
||||
</div>
|
||||
<div class="ui one column grid">
|
||||
<div class="right aligned column">
|
||||
<button class="ui green icon button" id="add_manual">
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<form class="ui form" id="modal_form">
|
||||
<input type="hidden" name="movimientos" value="[1]" />
|
||||
<div id="modal_movimientos">
|
||||
<div class="fields" data-movimiento="1">
|
||||
<div class="field">
|
||||
<label>Glosa</label>
|
||||
<input type="text" name="glosa1" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Cargo</label>
|
||||
<div class="ui left labeled input">
|
||||
<div class="ui basic label">$</div>
|
||||
<input type="text" name="cargo1" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Abono</label>
|
||||
<div class="ui left labeled input">
|
||||
<div class="ui basic label">$</div>
|
||||
<input type="text" name="abono1" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Saldo</label>
|
||||
<div class="ui left labeled input">
|
||||
<div class="ui basic label">$</div>
|
||||
<input type="text" name="saldo1" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="actions">
|
||||
<button class="ui approve button">
|
||||
Procesar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui modal" id="edit_modal" data-cartola="">
|
||||
<div class="header">
|
||||
Movimiento
|
||||
<div class="meta">
|
||||
<span id="edit_inmobiliaria"></span> |
|
||||
<span id="edit_cuenta"></span> |
|
||||
<span id="edit_fecha"></span> |
|
||||
<span id="edit_glosa"></span> |
|
||||
<span id="edit_cargo"></span> |
|
||||
<span id="edit_abono"></span> |
|
||||
<span id="edit_saldo"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<form class="ui form" id="edit_form">
|
||||
<input type="hidden" name="movimiento_id" value="" />
|
||||
<div class="equal width fields">
|
||||
<div class="field">
|
||||
<label>Centro de Costo</label>
|
||||
<div class="ui search selection dropdown">
|
||||
<input type="hidden" name="centro_costo_id" />
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="default text">Centro de Costo</div>
|
||||
<div class="menu">
|
||||
@foreach($centrosCostos as $centro)
|
||||
<div class="item" data-value="{{$centro->id}}">
|
||||
{{$centro->id}} - {{$centro->descripcion}}
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Categoría</label>
|
||||
<div class="ui input">
|
||||
<input type="text" name="categoria" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Detalle</label>
|
||||
<div class="ui input">
|
||||
<input type="text" name="detalle" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="equal width fields">
|
||||
<div class="field">
|
||||
<label>RUT</label>
|
||||
<div class="ui right labeled input">
|
||||
<input type="text" name="rut" />
|
||||
<div class="ui basic label">-<span id="digito"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Nombres</label>
|
||||
<div class="ui input">
|
||||
<input type="text" name="nombres" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Identificador</label>
|
||||
<div class="ui input">
|
||||
<input type="text" name="identificador" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui approve button">
|
||||
Editar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@include('layout.head.styles.datatables')
|
||||
@include('layout.body.scripts.datatables')
|
||||
@include('layout.body.scripts.rut')
|
||||
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
class Cartola {
|
||||
idx
|
||||
inmobiliaria = {
|
||||
rut: 0,
|
||||
razon: '',
|
||||
sigla: ''
|
||||
}
|
||||
cuenta = {
|
||||
id: 0,
|
||||
descripcion: ''
|
||||
}
|
||||
fecha = ''
|
||||
bancos = []
|
||||
movimientos = []
|
||||
saldo = 0
|
||||
ayer = 0
|
||||
|
||||
constructor(idx) {
|
||||
this.idx = idx
|
||||
}
|
||||
|
||||
get() {
|
||||
return {
|
||||
bancos: () => {
|
||||
const url = '{{$urls->api}}/inmobiliaria/' + this.inmobiliaria.rut + '/cuentas'
|
||||
diaria.loader().show()
|
||||
return fetchAPI(url).then(response => {
|
||||
diaria.loader().hide()
|
||||
if (!response) {
|
||||
this.bancos = []
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (json.cuentas.length === 0) {
|
||||
this.bancos = []
|
||||
return
|
||||
}
|
||||
this.bancos = json.cuentas.map(cuenta => {
|
||||
return {
|
||||
value: cuenta.id,
|
||||
text: cuenta.banco.nombre + ' - ' + cuenta.cuenta,
|
||||
name: cuenta.banco.nombre + ' - ' + cuenta.cuenta
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
ayer: (fecha) => {
|
||||
const url = '{{$urls->api}}/contabilidad/cartola/diaria/ayer'
|
||||
const body = new FormData()
|
||||
body.set('cuenta_id', this.cuenta.id)
|
||||
body.set('fecha', fecha.toISOString())
|
||||
return fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (json.cartola.length === 0) {
|
||||
return
|
||||
}
|
||||
this.ayer = json.cartola.saldo
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
draw() {
|
||||
return {
|
||||
form: ($form, inmobiliarias, first = false) => {
|
||||
const $fields = $('<div></div>').addClass('fields cartola').attr('data-cartola', this.idx)
|
||||
const $inmobiliarias_menu = $('<div></div>').addClass('menu')
|
||||
inmobiliarias.forEach(inmobiliaria => {
|
||||
$inmobiliarias_menu.append(
|
||||
$('<div></div>').addClass('item').attr('data-value', inmobiliaria.rut).html(inmobiliaria.razon)
|
||||
)
|
||||
})
|
||||
const $inmobiliarias_dropdown = $('<div></div>').addClass('ui search selection dropdown').attr('id', 'inmobiliaria' + this.idx).append(
|
||||
$('<input />').attr('type', 'hidden')//.attr('name', 'inmobiliaria_rut' + this.idx)
|
||||
).append(
|
||||
$('<i></i>').addClass('dropdown icon')
|
||||
).append(
|
||||
$('<div></div>').addClass('default text').html('Inmobiliaria')
|
||||
).append($inmobiliarias_menu)
|
||||
$fields.append(
|
||||
$('<div></div>').addClass('six wide field').append(
|
||||
$('<label></label>').attr('for', 'inmobiliaria' + this.idx).html('Sociedad')
|
||||
).append($inmobiliarias_dropdown)
|
||||
)
|
||||
const $cuentas_dropdown = $('<div></div>').addClass('ui search selection dropdown').attr('id', 'cuenta' + this.idx).append(
|
||||
$('<input />').attr('type', 'hidden').attr('name', 'cuenta_id' + this.idx)
|
||||
).append(
|
||||
$('<i></i>').addClass('dropdown icon')
|
||||
).append(
|
||||
$('<div></div>').addClass('default text').html('Banco - Cuenta')
|
||||
).append(
|
||||
$('<div></div>').addClass('menu')
|
||||
)
|
||||
$fields.append(
|
||||
$('<div></div>').addClass('four wide field').append(
|
||||
$('<label></label>').html('Banco - Cuenta')
|
||||
).append($cuentas_dropdown)
|
||||
)
|
||||
const $fecha_calendar = $('<div></div>').addClass('ui calendar').attr('id', 'fecha' + this.idx).append(
|
||||
$('<div></div>').addClass('ui left icon input').append(
|
||||
$('<i></i>').addClass('calendar icon')
|
||||
).append(
|
||||
$('<input />').attr('type', 'text')
|
||||
)
|
||||
)
|
||||
$fields.append(
|
||||
$('<div></div>').addClass('three wide field').append(
|
||||
$('<label></label>').attr('for', 'fecha' + this.idx).html('Fecha')
|
||||
).append($fecha_calendar)
|
||||
)
|
||||
$fields.append(
|
||||
$('<div></div>').addClass('field').append(
|
||||
$('<label></label>').html('Cartola')
|
||||
).append(
|
||||
$('<input />').addClass('ui invisible file input').attr('type', 'file').attr('name', 'file' + this.idx).attr('id', 'file' + this.idx)
|
||||
).append(
|
||||
$('<label></label>').addClass('ui icon button').attr('for', 'file' + this.idx).append(
|
||||
$('<i></i>').addClass('file icon')
|
||||
).append('Cargar')
|
||||
)
|
||||
)
|
||||
const $manual_checkbox = $('<div></div>').addClass('ui invisible checkbox').append(
|
||||
$('<input />').attr('type', 'checkbox').attr('name', 'manual' + this.idx).attr('id', 'manual' + this.idx)
|
||||
).append(
|
||||
$('<label></label>').addClass('image').attr('for', 'manual' + this.idx).append(
|
||||
$('<i></i>').addClass('large orange keyboard icon')
|
||||
)
|
||||
)
|
||||
|
||||
$fields.append($('<div></div>').addClass('field').append(
|
||||
$('<label></label>').html('Manual')
|
||||
).append($manual_checkbox))
|
||||
if (!first) {
|
||||
$fields.append(
|
||||
$('<div></div>').addClass('field').append(
|
||||
$('<label></label>').html('Eliminar')
|
||||
).append(
|
||||
$('<button></button>').addClass('ui red icon button').attr('data-cartola', this.idx).append(
|
||||
$('<i></i>').addClass('remove icon')
|
||||
).click(event => {
|
||||
const idx = $(event.currentTarget).data('cartola')
|
||||
diaria.cartolas().remove(idx)
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
$form.append($fields)
|
||||
|
||||
const cdo = JSON.parse(JSON.stringify(calendar_date_options))
|
||||
cdo['initialDate'] = new Date()
|
||||
cdo['maxDate'] = cdo['initialDate']
|
||||
cdo['onChange'] = (date, text, mode) => {
|
||||
this.fecha = date
|
||||
}
|
||||
this.fecha = cdo['initialDate']
|
||||
|
||||
$inmobiliarias_dropdown.dropdown({
|
||||
fireOnInit: true,
|
||||
onChange: (value, text, $choice) => {
|
||||
this.inmobiliaria.rut = value
|
||||
this.inmobiliaria.razon = text
|
||||
const inmobiliaria = diaria.data.inmobiliarias.find(inmobiliaria => inmobiliaria.rut === parseInt(value))
|
||||
if (typeof inmobiliaria !== 'undefined') {
|
||||
this.inmobiliaria.sigla = inmobiliaria.sigla
|
||||
}
|
||||
this.get().bancos(value).then(() => {
|
||||
$cuentas_dropdown.dropdown('change values', this.bancos)
|
||||
})
|
||||
},
|
||||
})
|
||||
$cuentas_dropdown.dropdown({
|
||||
fireOnInit: true,
|
||||
onChange: (value, text, $choice) => {
|
||||
this.cuenta.id = value
|
||||
this.cuenta.descripcion = text
|
||||
}
|
||||
})
|
||||
$fecha_calendar.calendar(cdo)
|
||||
$manual_checkbox.change(event => {
|
||||
const $element = $(event.currentTarget)
|
||||
const status = $element.checkbox('is checked')
|
||||
const $field = $element.parent().parent()
|
||||
const $file = $field.find('#file' + this.idx).parent()
|
||||
if (status) {
|
||||
$file.find('input').attr('type', 'hidden')
|
||||
$file.hide()
|
||||
|
||||
manual.data.inmobiliaria = $inmobiliarias_dropdown.dropdown('get text')
|
||||
manual.data.cuenta = $cuentas_dropdown.dropdown('get text')
|
||||
const fecha = $fecha_calendar.calendar('get date')
|
||||
manual.data.fecha = [fecha.getDate(), (fecha.getMonth()+1).toString().padStart(2, '0'), fecha.getFullYear()].join('-')
|
||||
manual.data.field = this.idx
|
||||
manual.$modal.modal('show')
|
||||
return
|
||||
}
|
||||
$file.find('input').attr('type', 'file')
|
||||
$file.show()
|
||||
})
|
||||
},
|
||||
diferencia: ($tbody, dateFormatter, numberFormatter) => {
|
||||
$tbody.append(
|
||||
$('<tr></tr>').append(
|
||||
$('<td></td>').html(this.inmobiliaria.razon)
|
||||
).append(
|
||||
$('<td></td>').html(this.cuenta.descripcion)
|
||||
).append(
|
||||
$('<td></td>').html(dateFormatter.format(this.fecha))
|
||||
).append(
|
||||
$('<td></td>').html(numberFormatter.format(this.ayer))
|
||||
).append(
|
||||
$('<td></td>').html(numberFormatter.format(this.saldo))
|
||||
).append(
|
||||
$('<td></td>').html(numberFormatter.format(this.saldo - this.ayer))
|
||||
)
|
||||
)
|
||||
},
|
||||
cartola: ($tbody, dateFormatter, numberFormatter) => {
|
||||
this.movimientos.forEach((row, idx) => {
|
||||
$tbody.append(
|
||||
[
|
||||
'<tr>',
|
||||
`<td>${this.inmobiliaria.sigla ?? this.inmobiliaria.razon}</td>`,
|
||||
`<td>${this.cuenta.descripcion}</td>`,
|
||||
`<td>${dateFormatter.format(row.fecha)}</td>`,
|
||||
`<td>${row.glosa}</td>`,
|
||||
`<td class="right aligned">${row.cargo === 0 ? '' : numberFormatter.format(row.cargo)}</td>`,
|
||||
`<td class="right aligned">${row.abono === 0 ? '' : numberFormatter.format(row.abono)}</td>`,
|
||||
`<td class="right aligned">${row.saldo === 0 ? '' : numberFormatter.format(row.saldo)}</td>`,
|
||||
'<td class="center aligned">',
|
||||
`<button class="ui icon button edit_movimiento" data-movimiento="${idx}">`,
|
||||
'<i class="edit icon"></i>',
|
||||
'</button>',
|
||||
'</td>',
|
||||
`<td>${(idx + 1).toString()}</td>`,
|
||||
].join("\n")
|
||||
)
|
||||
})
|
||||
Array.from(document.getElementsByClassName('edit_movimiento')).forEach(button => {
|
||||
button.addEventListener('click', function(clickEvent) {
|
||||
const idx = clickEvent.currentTarget.dataset['movimiento']
|
||||
const movimiento = this.movimientos[idx]
|
||||
const $modal = $('#edit_modal')
|
||||
$modal.attr('data-cartola', this.idx)
|
||||
$modal.find('#edit_inmobiliaria').html(this.inmobiliaria.razon)
|
||||
$modal.find('#edit_cuenta').html(this.cuenta.descripcion)
|
||||
$modal.find('#edit_fecha').html(dateFormatter.format(movimiento.fecha))
|
||||
$modal.find('#edit_glosa').html(movimiento.glosa)
|
||||
$modal.find('#edit_cargo').html(numberFormatter.format(movimiento.cargo))
|
||||
$modal.find('#edit_abono').html(numberFormatter.format(movimiento.abono))
|
||||
$modal.find('#edit_saldo').html(numberFormatter.format(movimiento.saldo))
|
||||
$modal.find('input[name="movimiento_id"]').val(movimiento.id)
|
||||
$modal.modal('show')
|
||||
}.bind(this))
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@php
|
||||
$columns = [
|
||||
'sociedad',
|
||||
'cuenta',
|
||||
'fecha',
|
||||
'glosa',
|
||||
'cargo',
|
||||
'abono',
|
||||
'saldo',
|
||||
'edit',
|
||||
'orden'
|
||||
];
|
||||
@endphp
|
||||
const diaria = {
|
||||
ids: {},
|
||||
data: {
|
||||
inmobiliarias: JSON.parse('{!! json_encode($inmobiliarias) !!}'),
|
||||
cartolasIdx: [],
|
||||
cartolas: [],
|
||||
movimientos: [],
|
||||
},
|
||||
dataTableConfig: {
|
||||
order: [[{{array_search('orden', $columns)}}, 'asc']],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: [{{implode(',', array_keys(array_filter($columns, function($column) {return in_array($column, ['fecha', 'cargo', 'abono', 'saldo', 'edit']);})))}}],
|
||||
width: '{{round((1/(count($columns) + 2)) * 100, 2)}}%'
|
||||
},
|
||||
{
|
||||
targets: [{{implode(',', array_keys(array_filter($columns, function($column) {return in_array($column, ['sociedad', 'cuenta', 'glosa']);})))}}],
|
||||
width: '{{round((1/(count($columns) + 2)) * 2 * 100, 2)}}%'
|
||||
},
|
||||
{
|
||||
targets: [{{array_search('orden', $columns)}}],
|
||||
visible: false
|
||||
}
|
||||
],
|
||||
},
|
||||
loaderStatus: true,
|
||||
loader() {
|
||||
return {
|
||||
show: () => {
|
||||
if (!this.loaderStatus) {
|
||||
$(this.ids.loader).show()
|
||||
this.loaderStatus = true
|
||||
}
|
||||
},
|
||||
hide: () => {
|
||||
if (this.loaderStatus) {
|
||||
$(this.ids.loader).hide()
|
||||
this.loaderStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
cartolas() {
|
||||
return {
|
||||
add: () => {
|
||||
let first = false
|
||||
if (this.data.cartolas.length === 0) {
|
||||
first = true
|
||||
}
|
||||
const idx = this.data.cartolas.reduce((prev, cartola) => Math.max(prev, cartola.idx), 0) + 1
|
||||
const cartola = new Cartola(idx)
|
||||
this.data.cartolas.push(cartola)
|
||||
this.data.cartolasIdx.push(idx)
|
||||
const form = $(this.ids.form)
|
||||
cartola.draw().form(form, this.data.inmobiliarias, first)
|
||||
$(this.ids.fields).attr('value', JSON.stringify(this.data.cartolasIdx))
|
||||
},
|
||||
remove: idx => {
|
||||
if (this.data.cartolas.length === 1) {
|
||||
return
|
||||
}
|
||||
const i = this.data.cartolasIdx.findIndex(value => value === idx)
|
||||
const cartolaIdx = this.data.cartolas.findIndex(cartola => cartola.idx === idx)
|
||||
$("div.cartola[data-cartola='" + idx + "']").remove()
|
||||
this.data.cartolasIdx.splice(i,1)
|
||||
this.data.cartolas.splice(cartolaIdx,1)
|
||||
$(this.ids.fields).attr('value', JSON.stringify(this.data.cartolasIdx))
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
return {
|
||||
empty: () => {
|
||||
Object.values(this.ids.table).forEach(id => $(id).find('tbody').html(''))
|
||||
},
|
||||
diferencia: () => {
|
||||
const $table = $(this.ids.table.diferencia)
|
||||
const $tbody = $table.find('tbody')
|
||||
$tbody.html('')
|
||||
const dateFormatter = new Intl.DateTimeFormat('es-CL', {
|
||||
year: 'numeric',
|
||||
month: 'numeric',
|
||||
day: 'numeric'
|
||||
})
|
||||
const numberFormatter = new Intl.NumberFormat('es-CL', {minimumFractionDigits: 0, maximumFractionDigits: 0})
|
||||
this.data.cartolas.forEach(cartola => {
|
||||
cartola.draw().diferencia($tbody, dateFormatter, numberFormatter)
|
||||
})
|
||||
},
|
||||
cartola: () => {
|
||||
const $table = $(this.ids.table.base)
|
||||
$table.DataTable().clear()
|
||||
$table.DataTable().destroy()
|
||||
const $tbody = $(this.ids.table.body)
|
||||
$tbody.html('')
|
||||
const dateFormatter = new Intl.DateTimeFormat('es-CL', {
|
||||
year: 'numeric',
|
||||
month: 'numeric',
|
||||
day: 'numeric'
|
||||
})
|
||||
const numberFormatter = new Intl.NumberFormat('es-CL', {minimumFractionDigits: 0, maximumFractionDigits: 0})
|
||||
this.data.cartolas.forEach(cartola => {
|
||||
cartola.draw().cartola($tbody, dateFormatter, numberFormatter)
|
||||
})
|
||||
$table.DataTable(this.dataTableConfig)
|
||||
},
|
||||
}
|
||||
},
|
||||
parse() {
|
||||
return {
|
||||
cartola: event => {
|
||||
const body = new FormData($(this.ids.form)[0])
|
||||
this.data.cartolas.forEach(cartola => {
|
||||
body.set('fecha' + cartola.idx, [cartola.fecha.getFullYear(), cartola.fecha.getMonth()+1, cartola.fecha.getDate()].join('-'))
|
||||
})
|
||||
const url = '{{$urls->api}}/contabilidad/cartola/diaria/procesar'
|
||||
diaria.loader().show()
|
||||
fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
diaria.loader().hide()
|
||||
this.draw().empty()
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (json.cartolas.length === 0) {
|
||||
return
|
||||
}
|
||||
Object.entries(json.cartolas).forEach(entry => {
|
||||
const cartolaIdx = this.data.cartolas.findIndex(cartola => cartola.idx === parseInt(entry[0]))
|
||||
this.data.cartolas[cartolaIdx].movimientos = []
|
||||
entry[1].movimientos.forEach((row, idx) => {
|
||||
const fecha = new Date(row.fecha)
|
||||
fecha.setDate(fecha.getDate() + 1)
|
||||
this.data.cartolas[cartolaIdx].movimientos[idx] = {
|
||||
id: row.id,
|
||||
fecha: fecha,
|
||||
glosa: row.glosa,
|
||||
documento: row.documento,
|
||||
cargo: row.cargo,
|
||||
abono: row.abono,
|
||||
saldo: row.saldo,
|
||||
centro: row.detalles?.centro_costo?.id ?? '',
|
||||
detalle: row.detalles?.detalle ?? '',
|
||||
categoria: row.detalles?.categoria ?? '',
|
||||
rut: row.detalles?.rut ?? '',
|
||||
nombres: row.detalles?.nombres ?? '',
|
||||
identificador: row.detalles?.identificador ?? ''
|
||||
}
|
||||
})
|
||||
const ayer = new Date(this.data.cartolas[cartolaIdx].fecha.getTime())
|
||||
ayer.setDate(this.data.cartolas[cartolaIdx].fecha.getDate() - 1)
|
||||
this.data.cartolas[cartolaIdx].saldo = entry[1].cartola.saldo
|
||||
this.data.cartolas[cartolaIdx].get().ayer(ayer)
|
||||
})
|
||||
this.draw().diferencia()
|
||||
this.draw().cartola()
|
||||
})
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(ids) {
|
||||
this.ids = ids
|
||||
|
||||
this.loader().hide()
|
||||
|
||||
$(this.ids.form).submit(event => {
|
||||
event.preventDefault()
|
||||
return false
|
||||
})
|
||||
$(this.ids.buttons.add).click(event => {
|
||||
this.cartolas().add()
|
||||
})
|
||||
$(this.ids.buttons.process).click(this.parse().cartola)
|
||||
$(this.ids.table.base).DataTable(this.dataTableConfig)
|
||||
|
||||
this.cartolas().add()
|
||||
|
||||
$(this.ids.editModal).modal({
|
||||
onApprove: $element => {
|
||||
const idx = $(this.ids.editModal).data('cartola')
|
||||
const id = $(this.ids.editModal).find('input[name="movimiento_id"]').val()
|
||||
const body = new FormData($(this.ids.editModal).find('form')[0])
|
||||
body.set('idx', idx)
|
||||
if (body.has('rut')) {
|
||||
body.set('rut', body.get('rut').replace(/\D/g, ''))
|
||||
body.set('digito', Rut.digitoVerificador(body.get('rut')))
|
||||
}
|
||||
const url = '{{$urls->api}}/contabilidad/movimiento/' + id + '/detalles'
|
||||
|
||||
return fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
response.json().then(json => {
|
||||
if (!json.status || json.movimiento === null || json.movimiento.detalles === null) {
|
||||
return
|
||||
}
|
||||
const idx = diaria.data.cartolas.findIndex(cartola => cartola.idx = json.input.idx)
|
||||
const movimiento = diaria.data.cartolas[idx].movimientos.find(movimiento => movimiento.id === id)
|
||||
movimiento.centro = json.movimiento.detalles.centro_costo.id
|
||||
movimiento.categoria = json.movimiento.detalles.categoria
|
||||
movimiento.detalle = json.movimiento.detalles.detalle
|
||||
movimiento.rut = json.movimiento.detalles.rut
|
||||
movimiento.digito = json.movimiento.detalles.digito
|
||||
movimiento.nombres = json.movimiento.detalles.nombres
|
||||
movimiento.identificador = json.movimiento.detalles.identificador
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
$(this.ids.editModal).find('.dropdown').dropdown()
|
||||
$(this.ids.editModal).find('[name="rut"]').on('input', function(event) {
|
||||
const rut = event.currentTarget.value
|
||||
const rut_clean = rut.replace(/\D/g, '')
|
||||
event.currentTarget.value = Rut.format(rut_clean)
|
||||
document.getElementById('digito').innerHTML = Rut.digitoVerificador(rut_clean)
|
||||
}.bind(this))
|
||||
const rut = $(this.ids.editModal).find('[name="rut"]')
|
||||
const rut_clean = rut.val().replace(/\D/g, '')
|
||||
rut.val(Rut.format(rut_clean))
|
||||
document.getElementById('digito').innerHTML = Rut.digitoVerificador(rut_clean)
|
||||
}
|
||||
}
|
||||
const manual = {
|
||||
ids: {},
|
||||
$modal: null,
|
||||
data: {
|
||||
inmobiliaria: '',
|
||||
cuenta: '',
|
||||
fecha: '',
|
||||
field: 0,
|
||||
movimientos: [
|
||||
{idx: 1}
|
||||
]
|
||||
},
|
||||
get movimientosIdx() {
|
||||
const $movimientosIdx = $(this.ids.form).find("[name='movimientos']")
|
||||
return JSON.parse($movimientosIdx.val())
|
||||
},
|
||||
set movimientosIdx(list) {
|
||||
const $movimientosIdx = $(this.ids.form).find("[name='movimientos']")
|
||||
$movimientosIdx.val(JSON.stringify(list))
|
||||
},
|
||||
update() {
|
||||
return {
|
||||
file: movimientos => {
|
||||
const $file = $("[name='file" + this.data.field + "']")
|
||||
$file.val(JSON.stringify(movimientos))
|
||||
}
|
||||
}
|
||||
},
|
||||
parse() {
|
||||
return {
|
||||
movimientos: () => {
|
||||
const $fields = $(this.ids.movimientos).find('.fields')
|
||||
const movimientos = []
|
||||
$fields.each((i, fields) => {
|
||||
const idx = $(fields).data('movimiento')
|
||||
const inputs = [
|
||||
'glosa',
|
||||
'cargo',
|
||||
'abono',
|
||||
'saldo'
|
||||
]
|
||||
const data = {}
|
||||
inputs.forEach(name => {
|
||||
data[name] = $(fields).find("[name='"+name+idx+"']").val()
|
||||
if (name !== 'glosa') {
|
||||
data[name] = parseInt(data[name]) || 0
|
||||
}
|
||||
})
|
||||
|
||||
movimientos.push(data)
|
||||
})
|
||||
this.update().file(movimientos)
|
||||
}
|
||||
}
|
||||
},
|
||||
movimiento() {
|
||||
return {
|
||||
add: () => {
|
||||
const idx = this.data.movimientos.reduce((prev, movimiento) => Math.max(prev, movimiento.idx), 0) + 1
|
||||
const movimiento = {
|
||||
idx
|
||||
}
|
||||
this.data.movimientos.push(movimiento)
|
||||
const movimientosidx = this.movimientosIdx
|
||||
movimientosidx.push(idx)
|
||||
this.movimientosIdx = movimientosidx
|
||||
this.draw().movimiento(idx)
|
||||
},
|
||||
remove: idx => {
|
||||
const movimientosIdx = this.movimientosIdx
|
||||
const i = movimientosIdx.findIndex(n => n === idx)
|
||||
movimientosIdx.splice(i, 1)
|
||||
const movimientoIdx = this.data.movimientos.findIndex(movimiento => movimiento.idx === idx)
|
||||
this.data.movimientos.splice(movimientoIdx, 1)
|
||||
$(this.ids.movimientos).find("[data-idx='"+idx+"']").parent().parent().remove()
|
||||
this.movimientosIdx = movimientosIdx
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
return {
|
||||
movimiento: idx => {
|
||||
$(this.ids.movimientos).append(
|
||||
$('<div></div>').addClass('fields').attr('data-movimiento', idx).append(
|
||||
'<div class="field">' + "\n"
|
||||
+ '<label>Glosa</label>' + "\n"
|
||||
+ '<input type="text" name="glosa' + idx + '" />' + "\n"
|
||||
+ '</div>' + "\n" +
|
||||
'<div class="field">' + "\n"
|
||||
+ '<label>Cargo</label>' + "\n"
|
||||
+ '<div class="ui left labeled input">' + "\n"
|
||||
+ '<div class="ui basic label">$</div>' + "\n"
|
||||
+ '<input type="text" name="cargo' + idx + '" />' + "\n"
|
||||
+ '</div>' + "\n"
|
||||
+ '</div>' + "\n" +
|
||||
'<div class="field">' + "\n"
|
||||
+ '<label>Abono</label>' + "\n"
|
||||
+ '<div class="ui left labeled input">' + "\n"
|
||||
+ '<div class="ui basic label">$</div>' + "\n"
|
||||
+ '<input type="text" name="abono' + idx + '" />' + "\n"
|
||||
+ '</div>' + "\n"
|
||||
+ '</div>' + "\n" +
|
||||
'<div class="field">' + "\n"
|
||||
+ '<label>Saldo</label>' + "\n"
|
||||
+ '<div class="ui left labeled input">' + "\n"
|
||||
+ '<div class="ui basic label">$</div>' + "\n"
|
||||
+ '<input type="text" name="saldo' + idx + '" />' + "\n"
|
||||
+ '</div>' + "\n"
|
||||
+ '</div>'
|
||||
).append(
|
||||
$('<div></div>').addClass('field').append(
|
||||
$('<label></label>').html('Eliminar')
|
||||
).append(
|
||||
$('<button></button>').addClass('ui red icon button').attr('type', 'button').attr('data-idx', idx).append(
|
||||
$('<i></i>').addClass('remove icon')
|
||||
).click(event => {
|
||||
const idx = $(event.currentTarget).data('idx')
|
||||
manual.movimiento().remove(idx)
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(ids) {
|
||||
this.ids = ids
|
||||
|
||||
$(this.ids.modal).modal({
|
||||
onShow: () => {
|
||||
$(this.ids.inmobiliaria).html(this.data.inmobiliaria)
|
||||
$(this.ids.cuenta).html(this.data.cuenta)
|
||||
$(this.ids.fecha).html(this.data.fecha)
|
||||
this.movimientos = []
|
||||
$(this.ids.form).trigger('reset')
|
||||
},
|
||||
onApprove: $element => {
|
||||
this.parse().movimientos()
|
||||
},
|
||||
onHide: $element => {
|
||||
this.parse().movimientos()
|
||||
}
|
||||
})
|
||||
this.$modal = $(this.ids.modal)
|
||||
$(this.ids.button).click(event => {
|
||||
this.movimiento().add()
|
||||
})
|
||||
$(this.ids.form).submit(event => {
|
||||
event.preventDefault()
|
||||
this.$modal.modal('hide')
|
||||
return false
|
||||
})
|
||||
}
|
||||
}
|
||||
$(document).ready(() => {
|
||||
diaria.setup({
|
||||
table: {
|
||||
base: '#tabla_movimientos',
|
||||
body: '#movimientos',
|
||||
diferencia: '#diferencia'
|
||||
},
|
||||
form: '#cartola_form',
|
||||
fields: '#fields',
|
||||
buttons: {
|
||||
add: '#add_button',
|
||||
process: '#process_button'
|
||||
},
|
||||
loader: '#loader',
|
||||
editModal: '#edit_modal'
|
||||
})
|
||||
manual.setup({
|
||||
modal: '#manual_modal',
|
||||
button: '#add_manual',
|
||||
inmobiliaria: '#modal_inmobiliaria',
|
||||
cuenta: '#modal_cuenta',
|
||||
fecha: '#modal_fecha',
|
||||
form: '#modal_form',
|
||||
movimientos: '#modal_movimientos'
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
345
app/resources/views/contabilidad/cartolas/import.blade.php
Normal file
345
app/resources/views/contabilidad/cartolas/import.blade.php
Normal file
@ -0,0 +1,345 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_content')
|
||||
<div class="ui container">
|
||||
<h1 class="ui header">
|
||||
Importar Cartola Diaria
|
||||
</h1>
|
||||
<div class="ui grid">
|
||||
<div class="right aligned sixteen wide column">
|
||||
<button class="ui green icon button" id="add_button">
|
||||
Agregar
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<form class="ui form" id="cartola_form">
|
||||
</form>
|
||||
<div class="ui two columns grid">
|
||||
<div class="column">
|
||||
<button class="ui icon button" id="process_button">
|
||||
<i class="file excel icon"></i>
|
||||
Procesar
|
||||
</button>
|
||||
</div>
|
||||
<div class="right aligned column">
|
||||
<div class="ui inline active loader" id="loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table class="ui celled table" id="movimientos" style="display: none;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Sigla</th>
|
||||
<th>Fecha</th>
|
||||
<th>Glosa</th>
|
||||
<th class="right aligned">Cargo</th>
|
||||
<th class="right aligned">Abono</th>
|
||||
<th class="right aligned">Saldo</th>
|
||||
<th class="center aligned">Centro de Costo</th>
|
||||
<th>Categoría</th>
|
||||
<th>Detalle</th>
|
||||
<th>RUT</th>
|
||||
<th>Nombres</th>
|
||||
<th class="center aligned">Identificador</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
@endsection
|
||||
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
class Cartola {
|
||||
props
|
||||
ids
|
||||
constructor({index, ids}) {
|
||||
this.props = {
|
||||
index
|
||||
}
|
||||
this.ids = ids
|
||||
}
|
||||
get sociedad() {
|
||||
return $(`#${this.ids.sociedad}${this.props.index}`).dropdown('get value')
|
||||
}
|
||||
get banco() {
|
||||
return $(`#${this.ids.banco}${this.props.index}`).dropdown('get value')
|
||||
}
|
||||
get mes() {
|
||||
return $(`#${this.ids.mes}${this.props.index}`).calendar('get date')
|
||||
}
|
||||
get file() {
|
||||
return $(`#archivo${this.props.index}`)[0].files[0]
|
||||
}
|
||||
get data() {
|
||||
return {
|
||||
sociedad_rut: this.sociedad,
|
||||
cuenta_id: this.banco,
|
||||
mes: [this.mes.getFullYear(), this.mes.getMonth() + 1, 1].join('-'),
|
||||
file: this.file,
|
||||
index: this.props.index
|
||||
}
|
||||
}
|
||||
draw({sociedades}) {
|
||||
const output = [
|
||||
`<div class="fields" data-idx="${this.props.index}">`,
|
||||
'<div class="five wide field">',
|
||||
'<label>Sociedad</label>',
|
||||
`<div class="ui search selection dropdown" id="${this.ids.sociedad}${this.props.index}">`,
|
||||
`<input type="hidden" name="sociedad_rut${this.props.index}" />`,
|
||||
'<i class="dropdown icon"></i>',
|
||||
'<div class="default text">Sociedad</div>',
|
||||
'<div class="menu">',
|
||||
...sociedades.map(sociedad => {
|
||||
return [
|
||||
`<div class="item" data-value="${sociedad.rut}">${sociedad.razon}</div>`
|
||||
].join("\n")
|
||||
}),
|
||||
'</div>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="four wide field">',
|
||||
'<label>Banco</label>',
|
||||
`<div class="ui search selection dropdown" id="${this.ids.banco}${this.props.index}">`,
|
||||
`<input type="hidden" name="banco_id${this.props.index}" />`,
|
||||
'<i class="dropdown icon"></i>',
|
||||
'<div class="default text">Banco</div>',
|
||||
'<div class="menu"></div>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="field">',
|
||||
'<label>Mes</label>',
|
||||
`<div class="ui calendar" id="${this.ids.mes}${this.props.index}">`,
|
||||
'<div class="ui input left icon">',
|
||||
'<i class="calendar icon"></i>',
|
||||
`<input type="text" name="mes${this.props.index}" placeholder="Mes" />`,
|
||||
'</div>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="field">',
|
||||
'<label>Archivo</label>',
|
||||
`<input type="file" class="ui invisible file input" name="archivo${this.props.index}" id="archivo${this.props.index}" />`,
|
||||
`<label for="archivo${this.props.index}" class="ui icon button" id="archivo_button">`,
|
||||
'<i class="file icon"></i>',
|
||||
'</label>',
|
||||
'</div>',
|
||||
]
|
||||
if (this.props.index > 1) {
|
||||
output.push(...[
|
||||
'<div class="field">',
|
||||
'<label> </label>',
|
||||
`<button class="ui red icon button remove" data-idx="${this.props.index}">`,
|
||||
'<i class="trash icon"></i>',
|
||||
'</button>',
|
||||
'</div>',
|
||||
])
|
||||
}
|
||||
output.push('</div>')
|
||||
return output.join("\n")
|
||||
}
|
||||
activate() {
|
||||
$(`#${this.ids.sociedad}${this.props.index}`).dropdown({
|
||||
onChange: (value, text, $choice) => {
|
||||
cartolas.fetch().bancos(value).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(data => {
|
||||
const dropdown = $(`#${this.ids.banco}${this.props.index}`)
|
||||
dropdown.dropdown('clear')
|
||||
dropdown.dropdown('change values', data.cuentas.map(cuenta => {
|
||||
const desc = [cuenta.banco.nombre, cuenta.cuenta].join(' - ')
|
||||
return {
|
||||
name: desc,
|
||||
value: cuenta.id,
|
||||
text: desc
|
||||
}
|
||||
}))
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
$(`#${this.ids.banco}${this.props.index}`).dropdown()
|
||||
const cdo = structuredClone(calendar_date_options)
|
||||
cdo.type = 'month'
|
||||
$(`#${this.ids.mes}${this.props.index}`).calendar(cdo)
|
||||
if (this.props.index > 1) {
|
||||
$(`.${this.ids.buttons.remove}[data-idx="${this.props.index}"]`).click(clickEvent => {
|
||||
const index = $(clickEvent.currentTarget).data('idx')
|
||||
this.remove(index)
|
||||
})
|
||||
}
|
||||
}
|
||||
remove(idx) {
|
||||
$(`.fields[data-idx=${idx}]`).remove()
|
||||
cartolas.data.cartolas = cartolas.data.cartolas.filter(cartola => cartola.props.index !== idx)
|
||||
cartolas.draw().form()
|
||||
}
|
||||
}
|
||||
class Movimiento {
|
||||
props
|
||||
constructor({sociedad, fecha, glosa, cargo, abono, saldo, categoria, detalle, centro_costo, rut, nombres, identificador}) {
|
||||
this.props = {
|
||||
sociedad,
|
||||
fecha,
|
||||
glosa,
|
||||
cargo,
|
||||
abono,
|
||||
saldo,
|
||||
categoria,
|
||||
detalle,
|
||||
centro_costo,
|
||||
rut,
|
||||
nombres,
|
||||
identificador
|
||||
}
|
||||
}
|
||||
draw({formatters}) {
|
||||
const fecha = new Date(this.props.fecha)
|
||||
return [
|
||||
'<tr>',
|
||||
`<td>${this.props.sociedad.sigla}</td>`,
|
||||
`<td>${formatters.date.format(fecha)}</td>`,
|
||||
`<td>${this.props.glosa}</td>`,
|
||||
`<td class="right aligned">${formatters.number.format(this.props.cargo ?? 0)}</td>`,
|
||||
`<td class="right aligned">${formatters.number.format(this.props.abono ?? 0)}</td>`,
|
||||
`<td class="right aligned">${formatters.number.format(this.props.saldo)}</td>`,
|
||||
`<td class="center aligned">${this.props.centro_costo ?? ''}</td>`,
|
||||
`<td>${this.props.categoria ?? ''}</td>`,
|
||||
`<td>${this.props.detalle ?? ''}</td>`,
|
||||
`<td>${this.props.rut ?? ''}</td>`,
|
||||
`<td>${this.props.nombres ?? ''}</td>`,
|
||||
`<td class="center aligned">${this.props.identificador ?? ''}</td>`,
|
||||
'</tr>'
|
||||
].join("\n")
|
||||
}
|
||||
}
|
||||
const cartolas = {
|
||||
ids: {},
|
||||
data: {
|
||||
sociedades: {!! json_encode($inmobiliarias) !!},
|
||||
bancos: {!! json_encode($bancos) !!},
|
||||
cartolas: [],
|
||||
movimientos: [],
|
||||
},
|
||||
formatters: {
|
||||
number: new Intl.NumberFormat('es-CL', {minimumFractionDigits: 0, maximumFractionDigits: 0}),
|
||||
date: new Intl.DateTimeFormat('es-CL', {dateStyle: 'short', timeStyle: 'short'})
|
||||
},
|
||||
add() {
|
||||
return {
|
||||
cartola: () => {
|
||||
const idx = cartolas.data.cartolas.length + 1
|
||||
const cartola = new Cartola({index: idx, ids: cartolas.ids.cartolas})
|
||||
cartolas.data.cartolas.push(cartola)
|
||||
cartolas.draw().form()
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
return {
|
||||
form: () => {
|
||||
const form = $(this.ids.form)
|
||||
form.empty()
|
||||
form.append(`<input type="hidden" name="cartolas" value="${this.data.cartolas.length}" />`)
|
||||
this.data.cartolas.forEach(cartola => {
|
||||
form.append(cartola.draw({sociedades: this.data.sociedades, bancos: this.data.bancos}))
|
||||
cartola.activate()
|
||||
})
|
||||
},
|
||||
movimientos: () => {
|
||||
const table = $(this.ids.movimientos)
|
||||
const tbody = table.find('tbody')
|
||||
tbody.empty()
|
||||
this.data.movimientos.forEach(movimiento => {
|
||||
tbody.append(movimiento.draw({formatters: this.formatters}))
|
||||
})
|
||||
table.show()
|
||||
}
|
||||
}
|
||||
},
|
||||
fetch() {
|
||||
return {
|
||||
bancos: sociedad_rut => {
|
||||
const url = `{{$urls->api}}/inmobiliaria/${sociedad_rut}/cuentas`
|
||||
return fetchAPI(url)
|
||||
}
|
||||
}
|
||||
},
|
||||
import() {
|
||||
return {
|
||||
cartolas: () => {
|
||||
const url = '{{$urls->api}}/contabilidad/cartolas/importar'
|
||||
const method = 'post'
|
||||
const body = new FormData()
|
||||
this.data.cartolas.forEach(cartola => {
|
||||
Object.entries(cartola.data).forEach(([key, value]) => {
|
||||
const name = `${key}[${cartola.props.index - 1}]`
|
||||
body.append(name, value)
|
||||
})
|
||||
})
|
||||
|
||||
fetchAPI(url, {method, body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(data => {
|
||||
if (data.errors.length > 0) {
|
||||
data.errors.forEach(errorData => {
|
||||
console.error(errorData)
|
||||
})
|
||||
}
|
||||
this.data.movimientos = data.movimientos.map(movimiento => new Movimiento(movimiento))
|
||||
this.draw().movimientos()
|
||||
})
|
||||
}).catch(error => {
|
||||
const table = $(this.ids.movimientos)
|
||||
const tbody = table.find('tbody')
|
||||
tbody.empty()
|
||||
table.hide()
|
||||
}).finally(() => {
|
||||
$(this.ids.loader).hide()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(ids) {
|
||||
this.ids = ids
|
||||
this.add().cartola()
|
||||
$(this.ids.buttons.add).click(() => {
|
||||
this.add().cartola()
|
||||
})
|
||||
$(this.ids.loader).hide()
|
||||
$(this.ids.form).submit(submitEvent => {
|
||||
submitEvent.preventDefault()
|
||||
$(this.ids.loader).show()
|
||||
this.import().cartolas()
|
||||
return false
|
||||
})
|
||||
$(this.ids.buttons.process).click(() => {
|
||||
$(this.ids.form).submit()
|
||||
})
|
||||
}
|
||||
}
|
||||
$(document).ready(() => {
|
||||
cartolas.setup({
|
||||
form: '#cartola_form',
|
||||
buttons: {
|
||||
add: '#add_button',
|
||||
process: '#process_button'
|
||||
},
|
||||
movimientos: '#movimientos',
|
||||
loader: '#loader',
|
||||
cartolas: {
|
||||
sociedad: 'sociedad',
|
||||
banco: 'banco',
|
||||
mes: 'mes',
|
||||
buttons: {
|
||||
remove: 'remove'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@ -15,7 +15,8 @@
|
||||
<div class="default text">Inmobiliaria</div>
|
||||
<div class="menu">
|
||||
@foreach ($inmobiliarias as $inmobiliaria)
|
||||
<div class="item" data-value="{{$inmobiliaria->rut}}">{{$inmobiliaria->razon}}</div>
|
||||
<div class="item"
|
||||
data-value="{{$inmobiliaria->rut}}">{{$inmobiliaria->razon}}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@ -40,7 +41,7 @@
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="file">Cartola</label>
|
||||
<input type="file" name="file" id="file" class="ui invisible file input" />
|
||||
<input type="file" name="file" id="file" class="ui invisible file input"/>
|
||||
<label for="file" class="ui icon button">
|
||||
<i class="file icon"></i>
|
||||
Cargar
|
||||
@ -119,20 +120,20 @@
|
||||
mes: '',
|
||||
movimientos: [],
|
||||
centrosCostos: {
|
||||
ingresos: JSON.parse('{!! json_encode(array_values(array_map(function(\Incoviba\Model\CentroCosto $centroCosto) {
|
||||
ingresos: JSON.parse('{!! json_encode(array_values(array_map(function(\Incoviba\Model\Contabilidad\CentroCosto $centroCosto) {
|
||||
return [
|
||||
'id' => $centroCosto->id,
|
||||
'descripcion' => $centroCosto->descripcion
|
||||
];
|
||||
}, array_filter($centrosCostos, function(\Incoviba\Model\CentroCosto $centroCosto) {
|
||||
}, array_filter($centrosCostos, function(\Incoviba\Model\Contabilidad\CentroCosto $centroCosto) {
|
||||
return $centroCosto->tipoCentro->descripcion === 'Ingreso';
|
||||
})))) !!}'),
|
||||
egresos: JSON.parse('{!! json_encode(array_values(array_map(function(\Incoviba\Model\CentroCosto $centroCosto) {
|
||||
egresos: JSON.parse('{!! json_encode(array_values(array_map(function(\Incoviba\Model\Contabilidad\CentroCosto $centroCosto) {
|
||||
return [
|
||||
'id' => $centroCosto->id,
|
||||
'descripcion' => $centroCosto->descripcion
|
||||
];
|
||||
}, array_filter($centrosCostos, function(\Incoviba\Model\CentroCosto $centroCosto) {
|
||||
}, array_filter($centrosCostos, function(\Incoviba\Model\Contabilidad\CentroCosto $centroCosto) {
|
||||
return $centroCosto->tipoCentro->descripcion === 'Egreso';
|
||||
})))) !!}'),
|
||||
}
|
||||
@ -170,7 +171,11 @@
|
||||
return
|
||||
}
|
||||
$(this.ids.form.banco).dropdown('change values', json.cuentas.map(cuenta => {
|
||||
return {value: cuenta.banco.id, text: cuenta.banco.nombre, name: cuenta.banco.nombre}
|
||||
return {
|
||||
value: cuenta.banco.id,
|
||||
text: cuenta.banco.nombre,
|
||||
name: cuenta.banco.nombre
|
||||
}
|
||||
})).dropdown('refresh')
|
||||
})
|
||||
})
|
||||
@ -247,12 +252,12 @@
|
||||
const movimientos = this.data.movimientos.map((movimiento, idx) => {
|
||||
const temp = structuredClone(movimiento)
|
||||
temp.fecha = movimiento.fecha.toISOString()
|
||||
let centro = $(".centro[data-index='" + (idx+1) + "']").dropdown('get value')
|
||||
let centro = $(".centro[data-index='" + (idx + 1) + "']").dropdown('get value')
|
||||
if (centro.length === 0) {
|
||||
centro = ''
|
||||
}
|
||||
temp.centro_costo = centro
|
||||
let detalle = $("[name='detalle" + (idx+1) + "']").val()
|
||||
let detalle = $("[name='detalle" + (idx + 1) + "']").val()
|
||||
if (typeof detalle === 'undefined') {
|
||||
detalle = ''
|
||||
}
|
||||
@ -294,7 +299,10 @@
|
||||
month: 'numeric',
|
||||
day: 'numeric'
|
||||
})
|
||||
const numberFormatter = new Intl.NumberFormat('es-CL', {minimumFractionDigits: 0, maximumFractionDigits: 0})
|
||||
const numberFormatter = new Intl.NumberFormat('es-CL', {
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
})
|
||||
this.data.movimientos.forEach((row, idx) => {
|
||||
tbody.append(
|
||||
$('<tr></tr>').append(
|
||||
@ -322,7 +330,7 @@
|
||||
})
|
||||
table.DataTable(this.dataTableConfig)
|
||||
},
|
||||
centrosDropdown: (idx, ingreso=true) => {
|
||||
centrosDropdown: (idx, ingreso = true) => {
|
||||
const menu = $('<div></div>').addClass('menu')
|
||||
let centros = this.data.centrosCostos.ingresos
|
||||
if (!ingreso) {
|
||||
|
225
app/resources/views/contabilidad/cuadratura.blade.php
Normal file
225
app/resources/views/contabilidad/cuadratura.blade.php
Normal file
@ -0,0 +1,225 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_content')
|
||||
<div class="ui container">
|
||||
<h1 class="ui header">
|
||||
Cuadratura de Cartola Mensual
|
||||
</h1>
|
||||
<form class="ui form" id="cuadratura_form">
|
||||
<div class="ui grid">
|
||||
<div class="fourteen wide column">
|
||||
<div class="fields">
|
||||
<div class="five wide field">
|
||||
<label>Inmobiliaria</label>
|
||||
<div class="ui selection search dropdown" id="inmobiliaria">
|
||||
<input type="hidden" name="inmobiliaria"/>
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="default text">Inmobiliaria</div>
|
||||
<div class="menu">
|
||||
@foreach ($inmobiliarias as $inmobiliaria)
|
||||
<div class="item" data-value="{{$inmobiliaria->rut}}">{{$inmobiliaria->razon}}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="two wide field">
|
||||
<label>Banco</label>
|
||||
<div class="ui selection search dropdown" id="banco">
|
||||
<input type="hidden" name="banco"/>
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="default text">Banco</div>
|
||||
<div class="menu"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Mes</label>
|
||||
<div class="ui calendar" id="mes">
|
||||
<div class="ui icon input">
|
||||
<i class="calendar icon"></i>
|
||||
<input type="text" name="mes"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="file">Cartola</label>
|
||||
<input type="file" name="file" id="file" class="ui invisible file input" />
|
||||
<label for="file" class="ui icon button">
|
||||
<i class="file icon"></i>
|
||||
Cargar
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="two wide middle aligned column">
|
||||
<button class="ui icon button">
|
||||
Procesar
|
||||
<i class="sync icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="ui two columns grid">
|
||||
<div class="column"></div>
|
||||
<div class="right aligned column">
|
||||
<div class="ui inline active loader" id="loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui fluid container" id="movimientos"></div>
|
||||
@endsection
|
||||
|
||||
@include('layout.head.styles.datatables')
|
||||
@include('layout.body.scripts.datatables')
|
||||
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
class LibroMayor {
|
||||
props
|
||||
constructor(props) {
|
||||
this.props = props
|
||||
}
|
||||
}
|
||||
class Cartola {
|
||||
|
||||
}
|
||||
const movimientos = {
|
||||
ids: {},
|
||||
data: {
|
||||
inmobiliaria: {
|
||||
rut: '',
|
||||
razon: ''
|
||||
},
|
||||
banco: {
|
||||
id: '',
|
||||
nombre: ''
|
||||
}
|
||||
},
|
||||
get() {
|
||||
return {
|
||||
bancos: inmobiliaria_rut => {
|
||||
const url = '{{$urls->api}}/inmobiliaria/' + inmobiliaria_rut + '/cuentas'
|
||||
$(this.ids.loader).show()
|
||||
return fetchAPI(url).then(response => {
|
||||
$(this.ids.loader).hide()
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (json.cuentas.length === 0) {
|
||||
return
|
||||
}
|
||||
$(this.ids.inputs.banco).dropdown('change values', json.cuentas.map(cuenta => {
|
||||
return {value: cuenta.banco.id, text: cuenta.banco.nombre, name: cuenta.banco.nombre}
|
||||
})).dropdown('refresh')
|
||||
})
|
||||
})
|
||||
},
|
||||
firstDate: inmobiliaria_rut => {
|
||||
const url = '{{$urls->api}}/inmobiliaria/' + inmobiliaria_rut + '/proyectos'
|
||||
$(this.ids.loader).show()
|
||||
return fetchAPI(url).then(response => {
|
||||
$(this.ids.loader).hide()
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (json.proyectos.length === 0) {
|
||||
return
|
||||
}
|
||||
const min = json.proyectos.reduce((min, proyecto) => {
|
||||
const date = new Date(proyecto.current_estado.fecha.date)
|
||||
if (min > date.getTime()) {
|
||||
return date.getTime()
|
||||
}
|
||||
return min
|
||||
}, (new Date()).getTime())
|
||||
$(this.ids.inputs.mes).calendar('set minDate', new Date(min))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
parse() {
|
||||
return {
|
||||
cartola: submitEvent => {
|
||||
submitEvent.preventDefault()
|
||||
const body = new FormData(document.getElementById('asignar_form'))
|
||||
body.set('mes', $(this.ids.inputs.mes).calendar('get date').toISOString())
|
||||
const url = '{{$urls->api}}/contabilidad/cartolas/procesar'
|
||||
$(this.ids.loader).show()
|
||||
fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
$(this.ids.loader).hide()
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (json.movimientos.length === 0) {
|
||||
return
|
||||
}
|
||||
this.data.movimientos = []
|
||||
json.movimientos.forEach((row, idx) => {
|
||||
const fecha = new Date(row.fecha)
|
||||
fecha.setDate(fecha.getDate() + 1)
|
||||
this.data.movimientos[idx] = {
|
||||
fecha: fecha,
|
||||
glosa: row.glosa,
|
||||
documento: row.documento,
|
||||
cargo: row.cargo,
|
||||
abono: row.abono,
|
||||
}
|
||||
})
|
||||
this.draw().cartola()
|
||||
})
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(ids) {
|
||||
this.ids = ids
|
||||
|
||||
$(this.ids.inputs.inmobiliaria).dropdown({
|
||||
fireOnInit: true,
|
||||
onChange: (value, text, $choice) => {
|
||||
this.data.inmobiliaria.rut = value
|
||||
this.data.inmobiliaria.razon = text
|
||||
this.get().bancos(value)
|
||||
this.get().firstDate(value)
|
||||
},
|
||||
})
|
||||
$(this.ids.inputs.banco).dropdown({
|
||||
fireOnInit: true,
|
||||
onChange: (value, text, $choice) => {
|
||||
this.data.banco.id = value
|
||||
this.data.banco.nombre = text
|
||||
}
|
||||
})
|
||||
$(this.ids.loader).hide()
|
||||
|
||||
calendar_date_options['type'] = 'month'
|
||||
const lastMonth = new Date()
|
||||
lastMonth.setDate(0)
|
||||
calendar_date_options['maxDate'] = lastMonth
|
||||
calendar_date_options['onChange'] = (date, text, mode) => {
|
||||
this.data.mes = text
|
||||
}
|
||||
$(this.ids.inputs.mes).calendar(calendar_date_options)
|
||||
$(this.ids.form).submit(this.parse().cartola)
|
||||
//$(this.ids.button).click(this.export().cartola)
|
||||
}
|
||||
}
|
||||
$(document).ready(() => {
|
||||
movimientos.setup({
|
||||
movimientos: '#movimientos',
|
||||
form: '#cuadratura_form',
|
||||
loader: '#loader',
|
||||
inputs: {
|
||||
inmobiliaria: '#inmobiliaria',
|
||||
banco: '#banco',
|
||||
mes: '#mes',
|
||||
cartola: '#file'
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
263
app/resources/views/contabilidad/depositos.blade.php
Normal file
263
app/resources/views/contabilidad/depositos.blade.php
Normal file
@ -0,0 +1,263 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_content')
|
||||
<div class="ui container">
|
||||
<h1 class="ui header">Depósitos a Plazo</h1>
|
||||
</div>
|
||||
<div class="ui stackable grid">
|
||||
<div class="two wide column"></div>
|
||||
<div class="twelve wide column">
|
||||
<table class="ui table" id="depositos">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Inmobiliaria</th>
|
||||
<th>Banco</th>
|
||||
<th>N° Depósito</th>
|
||||
<th>Capital</th>
|
||||
<th>Inicio</th>
|
||||
<th>Plazo</th>
|
||||
<th>Vencimiento</th>
|
||||
<th>Vencimiento ISO</th>
|
||||
<th>Monto al Vencimiento</th>
|
||||
<th>Tasa</th>
|
||||
<th>
|
||||
<button class="ui green icon button" id="add_button">
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($activos as $deposito)
|
||||
<tr>
|
||||
<td>{{$deposito->cuenta->inmobiliaria->razon}}</td>
|
||||
<td>{{$deposito->cuenta->banco->nombre}}</td>
|
||||
<td>{{$deposito->id}}</td>
|
||||
<td>{{$format->pesos($deposito->capital)}}</td>
|
||||
<td>{{$deposito->inicio->format('d-m-Y')}}</td>
|
||||
<td>{{$deposito->plazo()}}</td>
|
||||
<td>{{$deposito->termino->format('d-m-Y')}}</td>
|
||||
<td>{{$deposito->termino->format('Y-m-d')}}</td>
|
||||
<td>{{$format->pesos($deposito->futuro)}}</td>
|
||||
<td>{{$format->percent($deposito->tasa() * 100, 4)}}</td>
|
||||
<td>
|
||||
<button class="ui red icon button remove_button" data-deposito="{{$deposito->id}}">
|
||||
<i class="remove icon"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@foreach ($vencidos as $deposito)
|
||||
<tr class="yellow">
|
||||
<td>{{$deposito->cuenta->inmobiliaria->razon}}</td>
|
||||
<td>{{$deposito->cuenta->banco->nombre}}</td>
|
||||
<td>{{$deposito->id}}</td>
|
||||
<td>{{$format->pesos($deposito->capital)}}</td>
|
||||
<td>{{$deposito->inicio->format('d-m-Y')}}</td>
|
||||
<td>{{$deposito->plazo()}}</td>
|
||||
<td>{{$deposito->termino->format('d-m-Y')}}</td>
|
||||
<td>{{$deposito->termino->format('Y-m-d')}}</td>
|
||||
<td>{{$format->pesos($deposito->futuro)}}</td>
|
||||
<td>{{$format->percent($deposito->tasa() * 100, 4)}}</td>
|
||||
<td>
|
||||
<button class="ui red icon button remove_button" data-deposito="{{$deposito->id}}">
|
||||
<i class="remove icon"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui modal" id="add_modal">
|
||||
<div class="content">
|
||||
<form class="ui form" id="add_form">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label for="inmobiliaria">Inmobiliaria</label>
|
||||
<div class="ui search selection dropdown" id="inmobiliaria">
|
||||
<input type="hidden" name="inmobiliaria_rut" />
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="default text">Inmobiliaria</div>
|
||||
<div class="menu">
|
||||
@foreach ($inmobiliarias as $inmobiliaria)
|
||||
<div class="item" data-value="{{$inmobiliaria->rut}}">{{$inmobiliaria->razon}}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="banco">Banco</label>
|
||||
<div class="ui search selection dropdown" id="banco">
|
||||
<input type="hidden" name="banco_id" />
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="default text">Banco</div>
|
||||
<div class="menu"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="three wide field">
|
||||
<label for="identificador">N° Depósito</label>
|
||||
<input type="text" id="identificador" name="id" />
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label for="capital">Capital</label>
|
||||
<input type="number" id="capital" name="capital" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="futuro">Monto al Vencimiento</label>
|
||||
<input type="number" id="futuro" name="futuro" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label for="inicio">Inicio</label>
|
||||
<div class="ui calendar" id="inicio">
|
||||
<div class="ui left icon input">
|
||||
<i class="calendar icon"></i>
|
||||
<input type="text" name="inicio" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="termino">Vencimiento</label>
|
||||
<div class="ui calendar" id="termino">
|
||||
<div class="ui left icon input">
|
||||
<i class="calendar icon"></i>
|
||||
<input type="text" name="termino" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui approve button">Agregar</button>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@include('layout.head.styles.datatables')
|
||||
@include('layout.body.scripts.datatables')
|
||||
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
const depositos = {
|
||||
ids: {},
|
||||
data: {
|
||||
inmobiliaria: {
|
||||
rut: 0,
|
||||
razon: ''
|
||||
},
|
||||
banco: {
|
||||
id: 0,
|
||||
nombre: ''
|
||||
}
|
||||
},
|
||||
get() {
|
||||
return {
|
||||
bancos: inmobiliaria_rut => {
|
||||
const url = '{{$urls->api}}/inmobiliaria/' + inmobiliaria_rut + '/cuentas'
|
||||
return fetchAPI(url).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (json.cuentas.length === 0) {
|
||||
return
|
||||
}
|
||||
$(this.ids.forms.add.bancos).dropdown('change values', json.cuentas.map(cuenta => {
|
||||
return {value: cuenta.banco.id, text: cuenta.banco.nombre, name: cuenta.banco.nombre}
|
||||
})).dropdown('refresh')
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
add() {
|
||||
return {
|
||||
deposito: form => {
|
||||
const url = '{{$urls->api}}/contabilidad/depositos/add'
|
||||
const body = new FormData(form)
|
||||
const inicio = $(this.ids.forms.add.inicio).calendar('get date')
|
||||
const termino = $(this.ids.forms.add.termino).calendar('get date')
|
||||
body.set('inicio', [inicio.getFullYear(), inicio.getMonth()+1, inicio.getDate()].join('-'))
|
||||
body.set('termino', [termino.getFullYear(), termino.getMonth()+1, termino.getDate()].join('-'))
|
||||
|
||||
return fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (json.status) {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(ids) {
|
||||
this.ids = ids
|
||||
|
||||
$(this.ids.buttons.add).click(event => {
|
||||
$(this.ids.modals.add).modal('show')
|
||||
})
|
||||
$(this.ids.modals.add).modal({
|
||||
onApprove: $element => {
|
||||
$(this.ids.forms.add.base).submit()
|
||||
}
|
||||
})
|
||||
$(this.ids.forms.add.base).submit(event => {
|
||||
event.preventDefault()
|
||||
this.add().deposito(event.currentTarget)
|
||||
return false
|
||||
})
|
||||
$(this.ids.forms.add.inmobiliarias).dropdown({
|
||||
fireOnInit: true,
|
||||
onChange: (value, text, $choice) => {
|
||||
this.data.inmobiliaria.rut = value
|
||||
this.data.inmobiliaria.razon = text
|
||||
this.get().bancos(value)
|
||||
}
|
||||
})
|
||||
$(this.ids.forms.add.banco).dropdown({
|
||||
fireOnInit: true,
|
||||
onChange: (value, text, $choice) => {
|
||||
this.data.banco.id = value
|
||||
this.data.banco.nombre = text
|
||||
}
|
||||
})
|
||||
$(this.ids.forms.add.inicio).calendar(calendar_date_options)
|
||||
$(this.ids.forms.add.termino).calendar(calendar_date_options)
|
||||
|
||||
$(this.ids.table).dataTable({
|
||||
columnDefs: [{target: 7, visible: false, searchable: false}],
|
||||
order: [[7, 'desc'], [0, 'asc']]
|
||||
})
|
||||
}
|
||||
}
|
||||
$(document).ready(() => {
|
||||
depositos.setup({
|
||||
table: '#depositos',
|
||||
buttons: {
|
||||
add: '#add_button'
|
||||
},
|
||||
modals: {
|
||||
add: '#add_modal'
|
||||
},
|
||||
forms: {
|
||||
add: {
|
||||
base: '#add_form',
|
||||
inmobiliarias: '#inmobiliaria',
|
||||
bancos: '#banco',
|
||||
inicio: '#inicio',
|
||||
termino: '#termino'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
184
app/resources/views/contabilidad/informes/tesoreria.blade.php
Normal file
184
app/resources/views/contabilidad/informes/tesoreria.blade.php
Normal file
@ -0,0 +1,184 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@push('page_styles')
|
||||
<style>
|
||||
tr.bold > th {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('page_content')
|
||||
<div class="ui container">
|
||||
<h1 class="ui centered header">Informe de Tesorería</h1>
|
||||
<h4 class="ui centered sub header">{{$fecha->format('d M Y')}}</h4>
|
||||
<div class="ui grid">
|
||||
<div class="three wide column">
|
||||
<a href="/contabilidad/informes/xlsx/tesoreria/{{$fecha->format('Y-m-d')}}" target="_blank"
|
||||
style="color: inherit;">
|
||||
<div class="ui inverted green center aligned segment">
|
||||
Descargar en Excel <i class="file excel icon"></i>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui grid">
|
||||
<div class="four wide column">
|
||||
<table class="ui collapsing simple table">
|
||||
<tr>
|
||||
<td>Informe anterior</td>
|
||||
<td>
|
||||
<a href="{{$urls->base}}/contabilidad/informes/tesoreria/{{$anterior->format('Y-m-d')}}">
|
||||
{{$anterior->format('d/m/Y')}}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Informe actual</td>
|
||||
<td>{{$fecha->format('d/m/Y')}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="column"></div>
|
||||
<div class="four wide column">
|
||||
<table class="ui collapsing simple table">
|
||||
<tr>
|
||||
<td>Valor UF</td>
|
||||
<td class="right aligned">{{$format->pesos($UF->get($fecha), 2)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Valor Dólar</td>
|
||||
<td class="right aligned">{{$format->pesos($USD->get($fecha), 2)}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@if ($siguiente !== null)
|
||||
<div class="five wide column"></div>
|
||||
<div class="right aligned two wide column">
|
||||
<div class="ui segment">
|
||||
Siguiente
|
||||
<a href="{{$urls->base}}/contabilidad/informes/tesoreria/{{$siguiente->format('Y-m-d')}}">
|
||||
{{$siguiente->format('d/m/Y')}} >>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<table class="ui striped table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>EMPRESA</th>
|
||||
<th>Banco</th>
|
||||
<th>Cuenta</th>
|
||||
<th class="right aligned">Saldo Anterior</th>
|
||||
<th class="right aligned">Saldo Actual</th>
|
||||
<th class="right aligned">Diferencia</th>
|
||||
<th class="right aligned">FFMM</th>
|
||||
<th class="right aligned">DAP</th>
|
||||
<th class="right aligned">Saldo Empresa</th>
|
||||
<th class="right aligned">Total Cuentas</th>
|
||||
<th class="right aligned">Total FFMM</th>
|
||||
<th class="right aligned">Total DAP</th>
|
||||
<th class="right aligned">Caja Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($informes['sociedades'] as $sociedad_rut => $informe)
|
||||
@foreach ($informe->cuentas as $i => $cuenta)
|
||||
<tr>
|
||||
@if ($i === 0)
|
||||
<td rowspan="{{count($informe->cuentas)}}">{{$informe->sociedad->razon}}</td>
|
||||
@endif
|
||||
<td>{{$cuenta->banco}}</td>
|
||||
<td>{{$cuenta->numero}}</td>
|
||||
<td class="right aligned">{{$format->pesos($cuenta->anterior)}}</td>
|
||||
<td class="right aligned">{{$format->pesos($cuenta->actual)}}</td>
|
||||
<td class="right aligned">{{$format->pesos($cuenta->diferencia())}}</td>
|
||||
<td class="right aligned">{{$format->pesos($cuenta->ffmm)}}</td>
|
||||
<td class="right aligned">{{$format->pesos($cuenta->deposito)}}</td>
|
||||
<td class="right aligned">{{$format->pesos($cuenta->saldo())}}</td>
|
||||
@if ($i === 0)
|
||||
<td class="right aligned"
|
||||
rowspan="{{count($informe->cuentas)}}">{{$format->pesos($informe->total())}}</td>
|
||||
<td class="right aligned"
|
||||
rowspan="{{count($informe->cuentas)}}">{{$format->pesos($informe->ffmm())}}</td>
|
||||
<td class="right aligned"
|
||||
rowspan="{{count($informe->cuentas)}}">{{$format->pesos($informe->deposito())}}</td>
|
||||
<td class="right aligned"
|
||||
rowspan="{{count($informe->cuentas)}}">{{$format->pesos($informe->caja())}}</td>
|
||||
@endif
|
||||
</tr>
|
||||
@endforeach
|
||||
@endforeach
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="bold">
|
||||
<th colspan="3">TOTAL</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->anterior)}}</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->actual)}}</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->diferencia())}}</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->ffmm)}}</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->deposito)}}</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->saldo())}}</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->cuentas())}}</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->ffmms())}}</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->depositos())}}</th>
|
||||
<th class="right aligned">{{$format->pesos($informes['totales']->caja())}}</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<table class="ui table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>EMPRESA</th>
|
||||
<th class="right aligned">INGRESOS</th>
|
||||
<th class="right aligned">EGRESOS</th>
|
||||
<th>FECHA</th>
|
||||
<th>BANCO</th>
|
||||
<th>DESCRIPCIÓN</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($informes['movimientos'] as $tipo => $movimientos)
|
||||
@if ($tipo === 'capital dap')
|
||||
@if (count($movimientos['ingresos']) === 0 and count($movimientos['egresos']) === 0)
|
||||
@continue
|
||||
@endif
|
||||
<tr class="grey">
|
||||
<td colspan="6">{{strtoupper($tipo)}}</td>
|
||||
</tr>
|
||||
@foreach ($movimientos as $ms)
|
||||
@foreach ($ms as $movimiento)
|
||||
<tr>
|
||||
<td>{{$movimiento->cuenta->inmobiliaria->razon}}</td>
|
||||
<td class="right aligned">{{$format->pesos($movimiento->abono)}}</td>
|
||||
<td class="right aligned">{{$format->pesos($movimiento->cargo)}}</td>
|
||||
<td>{{$movimiento->fecha->format('d/m/Y')}}</td>
|
||||
<td>{{$movimiento->cuenta->banco->nombre}}</td>
|
||||
<td>{{$movimiento->glosa}}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endforeach
|
||||
@continue
|
||||
@endif
|
||||
@if (count($movimientos) === 0)
|
||||
@continue
|
||||
@endif
|
||||
<tr class="grey">
|
||||
<td colspan="6">{{strtoupper($tipo)}}</td>
|
||||
</tr>
|
||||
@foreach ($movimientos as $movimiento)
|
||||
<tr>
|
||||
<td>{{$movimiento->cuenta->inmobiliaria->razon}}</td>
|
||||
<td class="right aligned">{{$format->pesos($movimiento->abono)}}</td>
|
||||
<td class="red right aligned">{{$format->pesos($movimiento->cargo)}}</td>
|
||||
<td>{{$movimiento->fecha->format('d/m/Y')}}</td>
|
||||
<td>{{$movimiento->cuenta->banco->nombre}}</td>
|
||||
<td>{{$movimiento->glosa}}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endsection
|
1060
app/resources/views/contabilidad/movimientos.blade.php
Normal file
1060
app/resources/views/contabilidad/movimientos.blade.php
Normal file
File diff suppressed because it is too large
Load Diff
53
app/resources/views/contabilidad/tesoreria/import.blade.php
Normal file
53
app/resources/views/contabilidad/tesoreria/import.blade.php
Normal file
@ -0,0 +1,53 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_content')
|
||||
<div class="ui container">
|
||||
<h1 class="ui header">Importar Informe de Tesorería</h1>
|
||||
|
||||
<form class="ui form" id="import_form" enctype="multipart/form-data">
|
||||
<div class="ten wide field">
|
||||
<label>Informe</label>
|
||||
<div class="ui file action input">
|
||||
<input type="file" name="file[]" id="file" accept=".xlsx" multiple placeholder="Informe" />
|
||||
<label for="file" class="ui icon button">
|
||||
<i class="file icon"></i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui icon button">
|
||||
<i class="arrow up icon"></i>
|
||||
Subir
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
$(document).ready(() => {
|
||||
$('#import_form').submit(submitEvent => {
|
||||
submitEvent.preventDefault()
|
||||
|
||||
let formData = new FormData()
|
||||
formData.append('file', $('#file')[0].files[0])
|
||||
|
||||
const url = '{{$urls->api}}/contabilidad/tesoreria/import'
|
||||
const method = 'post'
|
||||
const body = new FormData(submitEvent.currentTarget)
|
||||
|
||||
fetchAPI(url, {method, body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(data => {
|
||||
console.log(data)
|
||||
|
||||
})
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
})
|
||||
return false
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@ -10,13 +10,11 @@
|
||||
<div class="ui two column grid">
|
||||
<div class="column">
|
||||
@include('home.cuotas_por_vencer')
|
||||
@include('home.cierres_vigentes')
|
||||
</div>
|
||||
<div class="column">
|
||||
@include('home.alertas')
|
||||
</div>
|
||||
<div class="column">
|
||||
@include('home.cierres_vigentes')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
@ -68,21 +68,6 @@
|
||||
const index = this.data.proyectos.findIndex(proyecto => proyecto.id === data.proyecto_id)
|
||||
this.data.proyectos[index].escrituras = data.escrituras
|
||||
})
|
||||
/*const index = this.data.proyectos.findIndex(proyecto => proyecto.id === proyecto_id)
|
||||
if (proyecto_id === 3) {
|
||||
this.data.proyectos[index].escrituras = {
|
||||
firmar: 20,
|
||||
pagar: 70,
|
||||
abonar: 3
|
||||
}
|
||||
}
|
||||
if (proyecto_id === 4) {
|
||||
this.data.proyectos[index].escrituras = {
|
||||
firmar: 0,
|
||||
pagar: 0,
|
||||
abonar: 2
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -132,7 +117,7 @@
|
||||
$('<div></div>').addClass('event').append(
|
||||
$('<div></div>').addClass('content').html(tipo)
|
||||
).append(
|
||||
$('<div></div>').addClass('meta').html(total + '/' + full + ' ' + formatter.format(Math.round(total / full * 10000) / 100).padStart(2, ' ') + '%')
|
||||
$('<div></div>').addClass('meta').html(total + '/' + full + ' [' + formatter.format(Math.round(total / full * 10000) / 100).padStart(2, ' ') + '%]')
|
||||
)
|
||||
)
|
||||
})
|
||||
|
@ -10,11 +10,6 @@
|
||||
<div class="column">
|
||||
Inmobiliarias
|
||||
</div>
|
||||
{{--<div class="right aligned column">
|
||||
<button class="ui icon button" type="button">
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
</div>--}}
|
||||
</h2>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui cards">
|
||||
@ -23,8 +18,6 @@
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
{{$inmobiliaria->abreviacion}}
|
||||
{{--<a href="{{$urls->base}}/inmobiliaria/{{$inmobiliaria->rut}}">
|
||||
</a>--}}
|
||||
</div>
|
||||
<div class="description">{{$inmobiliaria->razon}} {{$inmobiliaria->tipoSociedad->descripcion}}</div>
|
||||
<div class="meta">{{$inmobiliaria->rut()}}</div>
|
||||
|
330
app/resources/views/inmobiliarias/proveedores.blade.php
Normal file
330
app/resources/views/inmobiliarias/proveedores.blade.php
Normal file
@ -0,0 +1,330 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_content')
|
||||
<div class="ui container">
|
||||
<table class="ui table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th>Contacto</th>
|
||||
<th class="right aligned">
|
||||
<button class="ui green icon button" id="add_button">
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="proveedores">
|
||||
@foreach ($sociedades as $sociedad)
|
||||
<tr>
|
||||
<td>{{$sociedad->nombre}}</td>
|
||||
<td>{{$sociedad->contacto->nombreCompleto()}}</td>
|
||||
<td class="right aligned">
|
||||
<button class="ui icon button" data-sociedad="{{$sociedad->rut}}">
|
||||
<i class="edit icon"></i>
|
||||
</button>
|
||||
<button class="ui red icon button" data-sociedad="{{$sociedad->rut}}">
|
||||
<i class="remove icon"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="ui modal" id="add_modal">
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<div class="three wide field">
|
||||
<label for="rut">RUT</label>
|
||||
<div class="ui right labeled input">
|
||||
<input class="right aligned" type="text" id="rut" name="rut" placeholder="RUT" maxlength="10" required />
|
||||
<div class="ui basic label">-<span id="dv"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="five wide field">
|
||||
<label for="nombre">Nombre</label>
|
||||
<input type="text" id="nombre" name="nombre" placeholder="Nombre" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="razon">Razón Social</label>
|
||||
<input type="text" id="razon" name="razon" placeholder="Razón Social" required />
|
||||
</div>
|
||||
<div class="four wide field">
|
||||
<label for="tipo">Tipo</label>
|
||||
<div class="ui selection dropdown" id="tipo">
|
||||
<input type="hidden" name="tipo" required />
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="default text">Tipo</div>
|
||||
<div class="menu">
|
||||
@foreach ($tiposSociedades as $tipo)
|
||||
<div class="item" data-value="{{$tipo->id}}">{{$tipo->descripcion}}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui divider">Contacto</div>
|
||||
<div class="three wide field">
|
||||
<label for="rut_contacto">RUT</label>
|
||||
<div class="ui right labeled input">
|
||||
<input type="text" id="rut_contacto" name="rut_contacto" placeholder="RUT" maxlength="10" required />
|
||||
<div class="ui basic label">-<span id="dv_contacto"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fields">
|
||||
<div class="five wide field">
|
||||
<label for="nombre_contacto">Nombre</label>
|
||||
<input type="text" id="nombre_contacto" name="nombre_contacto" placeholder="Nombre" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="apellido_paterno_contacto">Apellido Paterno</label>
|
||||
<input type="text" id="apellido_paterno_contacto" name="apellido_paterno_contacto" placeholder="Apellido Paterno" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="apellido_materno_contacto">Apellido Materno</label>
|
||||
<input type="text" id="apellido_materno_contacto" name="apellido_materno_contacto" placeholder="Apellido Materno" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="email_contacto">Email</label>
|
||||
<input type="email" id="email_contacto" name="email_contacto" placeholder="Email" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="telefono_contacto">Teléfono</label>
|
||||
<div class="ui left labeled input">
|
||||
<div class="ui basic label">+56</div>
|
||||
<input type="text" id="telefono_contacto" name="telefono_contacto" placeholder="Teléfono" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui green approve button">Guardar</button>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
const proveedores = {
|
||||
ids: {
|
||||
modal: '',
|
||||
buttons: {
|
||||
add: '',
|
||||
edit: '',
|
||||
remove: ''
|
||||
},
|
||||
add: {
|
||||
form: '',
|
||||
rut: '',
|
||||
dv: '',
|
||||
nombre: '',
|
||||
razon: '',
|
||||
tipo: '',
|
||||
contacto: {
|
||||
rut: '',
|
||||
dv: '',
|
||||
nombre: '',
|
||||
apellido_paterno: '',
|
||||
apellido_materno: '',
|
||||
email: '',
|
||||
telefono: ''
|
||||
}
|
||||
},
|
||||
proveedores: ''
|
||||
},
|
||||
data: JSON.parse('{!! json_encode($sociedades) !!}'),
|
||||
add() {
|
||||
return {
|
||||
sociedad: () => {
|
||||
const data = {
|
||||
rut: $(this.ids.add.rut).val().replace(/\D/g, ''),
|
||||
digito: $(this.ids.add.dv).text(),
|
||||
nombre: $(this.ids.add.nombre).val(),
|
||||
razon: $(this.ids.add.razon).val(),
|
||||
tipo_sociedad_id: $(this.ids.add.tipo).dropdown('get value'),
|
||||
contacto: {
|
||||
rut: $(this.ids.add.contacto.rut).val().replace(/\D/g, ''),
|
||||
digito: $(this.ids.add.contacto.dv).text(),
|
||||
nombres: $(this.ids.add.contacto.nombre).val(),
|
||||
apellido_paterno: $(this.ids.add.contacto.apellido_paterno).val(),
|
||||
apellido_materno: $(this.ids.add.contacto.apellido_materno).val(),
|
||||
email: $(this.ids.add.contacto.email).val(),
|
||||
telefono: $(this.ids.add.contacto.telefono).val().replace(/\D/g, ''),
|
||||
}
|
||||
}
|
||||
const body = new FormData()
|
||||
body.append('sociedades[]', JSON.stringify(data))
|
||||
const url = '{{$urls->api}}/sociedades/add'
|
||||
const method = 'post'
|
||||
fetchAPI(url, {method, body})
|
||||
.then(response => (response) ? response.json() : null)
|
||||
.then(data => {
|
||||
if (data.sociedades !== null) {
|
||||
data.sociedades.forEach(sociedad => {
|
||||
const exists = this.data.find(s => s.rut === sociedad.rut)
|
||||
if (typeof exists !== 'undefined') {
|
||||
return
|
||||
}
|
||||
this.data.push(sociedad)
|
||||
})
|
||||
this.draw().sociedades()
|
||||
$(this.ids.modal).find('form.form').trigger('reset')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
edit() {},
|
||||
remove() {
|
||||
return {
|
||||
sociedad: rut => {
|
||||
const body = new FormData()
|
||||
body.append('sociedades_ruts[]', rut)
|
||||
const url = '{{$urls->api}}/sociedades/delete'
|
||||
const method = 'post'
|
||||
fetchAPI(url, {method, body})
|
||||
.then(response => (response) ? response.json() : null)
|
||||
.then(data => {
|
||||
if (data.sociedades !== null) {
|
||||
data.sociedades.forEach(sociedad => {
|
||||
if (sociedad.sociedad.rut !== rut) {
|
||||
return
|
||||
}
|
||||
if (!sociedad.deleted) {
|
||||
return
|
||||
}
|
||||
$(this.ids.proveedores).find(`button[data-sociedad="${rut}"]`).closest('tr').remove()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
return {
|
||||
sociedades: () => {
|
||||
$(this.ids.proveedores).empty()
|
||||
this.data.forEach(sociedad => {
|
||||
$(this.ids.proveedores).append(`
|
||||
<tr>
|
||||
<td>${sociedad.nombre}</td>
|
||||
<td>${sociedad.contacto.nombreCompleto}</td>
|
||||
<td class="right aligned">
|
||||
<button class="ui icon button" data-sociedad="${sociedad.rut}">
|
||||
<i class="edit icon"></i>
|
||||
</button>
|
||||
<button class="ui red icon button" data-sociedad="${sociedad.rut}">
|
||||
<i class="remove icon"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`)
|
||||
})
|
||||
$(this.ids.buttons.remove).click((e) => {
|
||||
this.remove().sociedad($(e.target).data('sociedad'))
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
formatters() {
|
||||
return {
|
||||
rut: value => {
|
||||
const rut = value.replace(/[^0-9]/g, '')
|
||||
if (rut.length <= 1) {
|
||||
return rut
|
||||
}
|
||||
return rut.replace(/\B(?=(\d{3})+(?!\d))/g, '.')
|
||||
},
|
||||
telefono: value => {
|
||||
const phone = value.replace(/[^0-9]/g, '')
|
||||
if (phone.length <= 1) {
|
||||
return phone
|
||||
}
|
||||
return phone.replace(/(\d{2})(\d{3})(\d{4})/, '$1 $2 $3')
|
||||
}
|
||||
}
|
||||
},
|
||||
digitoVerificador(value) {
|
||||
let rut = value.replace(/[^0-9kK]/g, '')
|
||||
if (rut.length < 1) {
|
||||
return ''
|
||||
}
|
||||
let suma = 0
|
||||
let mul = 2
|
||||
for (let i = rut.length-1; i >= 0; i--) {
|
||||
suma += parseInt(rut[i]) * mul
|
||||
mul = (mul + 1) % 8 || 2
|
||||
}
|
||||
const dv = 11 - suma % 11
|
||||
return dv === 10 ? 'K' : (dv === 11 ? '0' : dv.toString())
|
||||
},
|
||||
setup(ids) {
|
||||
this.ids = ids
|
||||
$(this.ids.buttons.add).click(() => {
|
||||
$(this.ids.modal).modal('show')
|
||||
})
|
||||
$(this.ids.add.rut).on('input', (e) => {
|
||||
e.target.value = this.formatters().rut(e.target.value)
|
||||
$(this.ids.add.dv).text(this.digitoVerificador(e.target.value))
|
||||
})
|
||||
if ($(this.ids.add.rut).val().length > 0) {
|
||||
$(this.ids.add.rut).val(this.formatters().rut($(this.ids.add.rut).val()))
|
||||
$(this.ids.add.dv).text(this.digitoVerificador($(this.ids.add.rut).val()))
|
||||
}
|
||||
$(this.ids.tipo).dropdown()
|
||||
$(this.ids.add.contacto.rut).on('input', (e) => {
|
||||
e.target.value = this.formatters().rut(e.target.value)
|
||||
$(this.ids.add.contacto.dv).text(this.digitoVerificador(e.target.value))
|
||||
})
|
||||
if ($(this.ids.add.contacto.rut).val().length > 0) {
|
||||
$(this.ids.add.contacto.rut).val(this.formatters().rut($(this.ids.add.contacto.rut).val()))
|
||||
$(this.ids.add.contacto.dv).text(this.digitoVerificador($(this.ids.add.contacto.rut).val()))
|
||||
}
|
||||
$(this.ids.add.contacto.telefono).on('input', (e) => {
|
||||
e.target.value = this.formatters().telefono(e.target.value)
|
||||
})
|
||||
if ($(this.ids.add.contacto.telefono).val().length > 0) {
|
||||
$(this.ids.add.contacto.telefono).val(this.formatters().telefono($(this.ids.add.contacto.telefono).val()))
|
||||
}
|
||||
$(this.ids.modal).modal({
|
||||
onApprove: () => {
|
||||
this.add().sociedad()
|
||||
}
|
||||
})
|
||||
$(this.ids.buttons.remove).click((e) => {
|
||||
this.remove().sociedad($(e.target).data('sociedad'))
|
||||
})
|
||||
}
|
||||
}
|
||||
$(document).ready(() => {
|
||||
proveedores.setup({
|
||||
modal: '#add_modal',
|
||||
buttons: {
|
||||
add: '#add_button',
|
||||
edit: '.edit',
|
||||
remove: '.remove'
|
||||
},
|
||||
add: {
|
||||
form: '#add_modal form.form',
|
||||
rut: '#rut',
|
||||
dv: '#dv',
|
||||
nombre: '#nombre',
|
||||
razon: '#razon',
|
||||
tipo: '#tipo',
|
||||
contacto: {
|
||||
rut: '#rut_contacto',
|
||||
dv: '#dv_contacto',
|
||||
nombre: '#nombre_contacto',
|
||||
apellido_paterno: '#apellido_paterno_contacto',
|
||||
apellido_materno: '#apellido_materno_contacto',
|
||||
email: '#email_contacto',
|
||||
telefono: '#telefono_contacto'
|
||||
}
|
||||
},
|
||||
proveedores: '#proveedores'
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@ -2,6 +2,13 @@
|
||||
Contabilidad
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
<div class="item">
|
||||
<i class="dropdown icon"></i>
|
||||
Informes
|
||||
<div class="menu">
|
||||
<a class="item" href="{{$urls->base}}/contabilidad/informes/tesoreria/{{$hoy->sub(new DateInterval('P1D'))->format('Y-m-d')}}">Tesorería</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<i class="dropdown icon"></i>
|
||||
<a class="text" href="{{$urls->base}}/contabilidad/centros_costos">Centros de Costos</a>
|
||||
@ -9,5 +16,14 @@
|
||||
<a class="item" href="{{$urls->base}}/contabilidad/centros_costos/asignar">Asignar en Cartola</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<i class="dropdown icon"></i>
|
||||
<a class="text" href="{{$urls->base}}/contabilidad/cartolas/diaria">Cartola Diaria</a>
|
||||
<div class="menu">
|
||||
<a class="item" href="{{$urls->base}}/contabilidad/cartolas/importar">Importar</a>
|
||||
</div>
|
||||
</div>
|
||||
<a class="item" href="{{$urls->base}}/contabilidad/depositos">Depósitos a Plazo</a>
|
||||
<a class="item" href="{{$urls->base}}/contabilidad/movimientos">Movimientos</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -33,6 +33,7 @@
|
||||
</div>--}}
|
||||
{{--<a class="item" href="{{$urls->base}}/ventas/precios/importar">Importar Precios</a>--}}
|
||||
{{--<a class="item" href="{{$urls->base}}/ventas/cierres/evaluar">Evaluar Cierre</a>--}}
|
||||
<a class="item" href="{{$urls->base}}/ventas/facturacion">Facturación</a>
|
||||
<a class="item" href="{{$urls->base}}/ventas/add">
|
||||
Nueva Venta
|
||||
<i class="plus icon"></i>
|
||||
|
@ -1,7 +1,12 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js" integrity="sha512-3gJwYpMe3QewGELv8k/BX9vcqhryRdzRMxVfq6ngyWXwo03GFEzjsUm8Q7RZcHPHksttq7/GFoxjCVUjkjvPdw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.2/semantic.min.js" integrity="sha512-5cguXwRllb+6bcc2pogwIeQmQPXEzn2ddsqAexIBhh7FO1z5Hkek1J9mrK2+rmZCTU6b6pERxI7acnp1MpAg4Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.3/semantic.min.js" integrity="sha512-gnoBksrDbaMnlE0rhhkcx3iwzvgBGz6mOEj4/Y5ZY09n55dYddx6+WYc72A55qEesV8VX2iMomteIwobeGK1BQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
class APIClient {
|
||||
static fetch(url, options=null) {
|
||||
return fetchAPI(url, options)
|
||||
}
|
||||
}
|
||||
function fetchAPI(url, options=null) {
|
||||
if (options === null) {
|
||||
options = {}
|
||||
@ -10,7 +15,7 @@
|
||||
options['headers'] = {}
|
||||
}
|
||||
if (!Object.hasOwn(options['headers'], 'Authorization')) {
|
||||
options['headers']['Authorization'] = 'Bearer {{md5($API_KEY)}}'
|
||||
options['headers']['Authorization'] = 'Bearer {{md5($API_KEY)}}{{($login->isIn()) ? $login->getSeparator() . $login->getToken() : ''}}'
|
||||
}
|
||||
return fetch(url, options).then(response => {
|
||||
if (response.ok) {
|
||||
@ -21,6 +26,28 @@
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
const datatables_defaults = {
|
||||
language: {
|
||||
emptyTable: 'No hay datos disponibles',
|
||||
info: 'Mostrando _START_ a _END_ de _TOTAL_ registros',
|
||||
infoEmpty: 'Mostrando desde 0 a 0 de 0 registros',
|
||||
infoFiltered: '(filtrado de _MAX_ registros totales)',
|
||||
lengthMenu: 'Mostrar _MENU_ registros',
|
||||
loadingRecords: 'Cargando...',
|
||||
search: 'Buscar:',
|
||||
zeroRecords: 'No se encontraron registros',
|
||||
paginate: {
|
||||
first: 'Primero',
|
||||
last: 'Último',
|
||||
next: 'Siguiente',
|
||||
previous: 'Anterior',
|
||||
},
|
||||
aria: {
|
||||
orderable: 'Ordenar por esta columna',
|
||||
orderableReverse: 'Ordenar por esta columna en orden inverso',
|
||||
}
|
||||
}
|
||||
}
|
||||
const calendar_date_options = {
|
||||
type: 'date',
|
||||
firstDayOfWeek: 1,
|
||||
@ -28,9 +55,12 @@
|
||||
monthFirst: false,
|
||||
text: {
|
||||
days: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa'],
|
||||
dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab'],
|
||||
dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
|
||||
months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
|
||||
monthsShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'],
|
||||
today: 'Hoy'
|
||||
today: 'Hoy',
|
||||
now: 'Ahora',
|
||||
},
|
||||
formatter: {
|
||||
date: 'DD-MM-YYYY'
|
||||
|
@ -0,0 +1,3 @@
|
||||
@push('page_scripts')
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js" integrity="sha512-a+SUDuwNzXDvz4XrIcXHuCf089/iJAoN4lmrXJg18XnduKK6YlDHNRalv4yd1N40OKI80tFidF+rqTFKGPoWFQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
@endpush
|
@ -1,4 +1,4 @@
|
||||
@push('page_scripts')
|
||||
<script type="text/javascript" src="https://cdn.datatables.net/1.13.5/js/jquery.dataTables.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.datatables.net/1.13.5/js/dataTables.semanticui.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.datatables.net/2.0.3/js/dataTables.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/2.0.3/js/dataTables.semanticui.min.js"></script>
|
||||
@endpush
|
||||
|
@ -0,0 +1,9 @@
|
||||
@push('page_scripts')
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.9/pdfmake.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdn.datatables.net/buttons/3.0.1/js/dataTables.buttons.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/buttons/3.0.1/js/buttons.semanticui.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/buttons/3.0.1/js/buttons.colVis.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/buttons/3.0.1/js/buttons.html5.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/buttons/3.0.1/js/buttons.print.min.js"></script>
|
||||
@endpush
|
@ -0,0 +1,5 @@
|
||||
@push('page_scripts')
|
||||
<script src="https://cdn.datatables.net/datetime/1.5.2/js/dataTables.dateTime.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/searchbuilder/1.7.0/js/dataTables.searchBuilder.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/searchbuilder/1.7.0/js/searchBuilder.semanticui.js"></script>
|
||||
@endpush
|
3
app/resources/views/layout/body/scripts/luxon.blade.php
Normal file
3
app/resources/views/layout/body/scripts/luxon.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
@push('page_scripts')
|
||||
<script src="https://cdn.jsdelivr.net/npm/luxon@3.4.4/build/global/luxon.min.js" integrity="sha256-7NQm0bhvDJKosL8d+6ZgSi2LxZCIcA/TD087GLEBO9M=" crossorigin="anonymous"></script>
|
||||
@endpush
|
26
app/resources/views/layout/body/scripts/rut.blade.php
Normal file
26
app/resources/views/layout/body/scripts/rut.blade.php
Normal file
@ -0,0 +1,26 @@
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
class Rut {
|
||||
static digitoVerificador(rut) {
|
||||
if (rut.length === 0) {
|
||||
return ''
|
||||
}
|
||||
let M = 0, S = 1
|
||||
for (; rut; rut = Math.floor(rut / 10)) {
|
||||
S = (S + rut % 10 * (9 - M++ % 6)) % 11
|
||||
}
|
||||
return S ? S - 1 : 'K'
|
||||
}
|
||||
static format(rut) {
|
||||
if (rut.length === 0) {
|
||||
return ''
|
||||
}
|
||||
rut.replace(/\D/g, '')
|
||||
return rut.replace(/^(\d{1,2})(\d{3})(\d{3})$/, '$1.$2.$3')
|
||||
}
|
||||
static validar(rut, digito) {
|
||||
return Rut.digitoVerificador(rut) === digito
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endpush
|
@ -1,3 +1,3 @@
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.2/semantic.min.css" integrity="sha512-n//BDM4vMPvyca4bJjZPDh7hlqsQ7hqbP9RH18GF2hTXBY5amBwM2501M0GPiwCU/v9Tor2m13GOTFjk00tkQA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.3/semantic.min.css" integrity="sha512-3quBdRGJyLy79hzhDDcBzANW+mVqPctrGCfIPosHQtMKb3rKsCxfyslzwlz2wj1dT8A7UX+sEvDjaUv+WExQrA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
|
||||
@stack('page_styles')
|
||||
|
@ -1,3 +1,3 @@
|
||||
@push('page_styles')
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.5/css/dataTables.semanticui.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/2.0.3/css/dataTables.semanticui.min.css" />
|
||||
@endpush
|
||||
|
@ -0,0 +1,3 @@
|
||||
@push('page_styles')
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/buttons/3.0.0/css/buttons.semanticui.min.css" />
|
||||
@endpush
|
@ -0,0 +1,4 @@
|
||||
@push('page_styles')
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/datetime/1.5.2/css/dataTables.dateTime.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/searchbuilder/1.7.0/css/searchBuilder.dataTables.min.css" />
|
||||
@endpush
|
@ -16,29 +16,30 @@
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@include('layout.body.scripts.cryptojs')
|
||||
|
||||
@push('page_scripts')
|
||||
<script type="text/javascript">
|
||||
function encryptPassword(password) {
|
||||
const passphrase = Math.floor(Math.random() * Date.now()).toString()
|
||||
const encrypted = CryptoJS.AES.encrypt(password, passphrase)
|
||||
return [passphrase, encrypted.toString()].join('')
|
||||
}
|
||||
function sendLogin(name, password) {
|
||||
const data = new FormData()
|
||||
data.append('name', name)
|
||||
data.append('password', password)
|
||||
return fetch('{{$urls->base}}/login', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
const method = 'post'
|
||||
const headers = {
|
||||
Accept: 'json'
|
||||
},
|
||||
body: data
|
||||
}).then(response => {
|
||||
}
|
||||
const body = new FormData()
|
||||
body.append('name', name)
|
||||
body.append('password', encryptPassword(password))
|
||||
return fetch('{{$urls->base}}/login', {method, headers, body}).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
}).then(data => {
|
||||
if (data.login === true) {
|
||||
@if(isset($redirect_uri))
|
||||
window.location = '{{$redirect_uri}}'
|
||||
@else
|
||||
window.location = '{{$urls->base}}'
|
||||
@endif
|
||||
window.location = '{{(isset($redirect_uri)) ? $redirect_uri : $urls->base}}'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
<form id="search_form" class="ui form" action="{{$urls->base}}/search" method="post">
|
||||
<div class="field">
|
||||
<div class="ui fluid input" data-tooltip="Para buscar frases se deben encerrar entre comillas. ej, 'portal la viña' o "portal la viña"" data-position="bottom left">
|
||||
<div class="ui fluid input" data-tooltip="Para buscar frases se deben encerrar entre comillas. ej, 'portal la viña' o "portal la viña"" data-position="top right">
|
||||
<input type="text" name="query" />
|
||||
</div>
|
||||
</div>
|
||||
@ -56,7 +56,7 @@
|
||||
unidad.html(unidad.html() + ' (I)')
|
||||
}
|
||||
propietario = $('<a></a>')
|
||||
.attr('href','{{$urls->base}}/search/' + encodeURIComponent(this.venta.propietario.nombre_completo) + '/propietario')
|
||||
.attr('href','{{$urls->base}}/search/"' + encodeURIComponent(this.venta.propietario.nombre_completo) + '"/propietario')
|
||||
.html(this.venta.propietario.nombre_completo)
|
||||
fecha = dateFormatter.format(new Date(this.venta.fecha))
|
||||
if (typeof this.venta.entrega !== 'undefined') {
|
||||
@ -96,6 +96,10 @@
|
||||
id: '',
|
||||
data: [],
|
||||
table: null,
|
||||
queues: {
|
||||
unidades: [],
|
||||
ventas: []
|
||||
},
|
||||
get: function() {
|
||||
return {
|
||||
results: () => {
|
||||
@ -122,34 +126,33 @@
|
||||
}
|
||||
const progress = this.draw().progress(data.results.length)
|
||||
const promises = []
|
||||
data.results.forEach(row => {
|
||||
if (row.tipo === 'venta') {
|
||||
return promises.push(this.get().venta(row.id).then(json => {
|
||||
if (json.venta === null) {
|
||||
this.queues.ventas = data.results.filter(row => row.tipo === 'venta').map(row => row.id)
|
||||
this.queues.unidades = data.results.filter(row => row.tipo !== 'venta').map(row => row.id)
|
||||
promises.push(this.get().ventas().then(arrays => {
|
||||
arrays.forEach(json => {
|
||||
if (json.ventas.length === 0) {
|
||||
console.debug(json)
|
||||
return
|
||||
}
|
||||
const venta = json.venta
|
||||
json.ventas.forEach(venta => {
|
||||
progress.progress('increment')
|
||||
const r = new Row({unidad: venta.propiedad.unidades[0], proyecto: venta.proyecto})
|
||||
r.venta = venta
|
||||
this.data.push(r)
|
||||
}).catch(error => {
|
||||
progress.progress('increment')
|
||||
console.error(row)
|
||||
console.error(error)
|
||||
})
|
||||
})
|
||||
}))
|
||||
promises.push(this.get().unidades().then(arrays => {
|
||||
arrays.forEach(json => {
|
||||
if (json.unidades.length === 0) {
|
||||
return
|
||||
}
|
||||
promises.push(this.get().unidad(row.id).then(json => {
|
||||
const unidad = json.unidad
|
||||
json.unidades.forEach(unidad => {
|
||||
progress.progress('increment')
|
||||
this.data.push(new Row({unidad: unidad, proyecto: unidad.proyecto_tipo_unidad.proyecto}))
|
||||
}).catch(error => {
|
||||
progress.progress('increment')
|
||||
console.error(row)
|
||||
console.error(error)
|
||||
}))
|
||||
})
|
||||
})
|
||||
}))
|
||||
Promise.all(promises).then(() => {
|
||||
this.sort()
|
||||
this.draw().clear()
|
||||
@ -157,22 +160,43 @@
|
||||
})
|
||||
})
|
||||
},
|
||||
unidad: id => {
|
||||
const url = '{{$urls->api}}/ventas/unidad/' + id
|
||||
return fetchAPI(url).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
unidades: () => {
|
||||
const url = '{{$urls->api}}/search/ventas/unidades'
|
||||
const chunks = []
|
||||
for (let i = 0; i < this.queues.unidades.length; i += 100) {
|
||||
chunks.push(this.queues.unidades.slice(i, i + 100))
|
||||
}
|
||||
})
|
||||
},
|
||||
venta: id => {
|
||||
const url = '{{$urls->api}}/venta/' + id
|
||||
return fetchAPI(url).then(response => {
|
||||
const promises = []
|
||||
chunks.forEach(ids => {
|
||||
const body = new FormData()
|
||||
body.set('unidades', ids)
|
||||
promises.push(fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json()
|
||||
}))
|
||||
})
|
||||
return Promise.all(promises)
|
||||
},
|
||||
ventas: () => {
|
||||
const url = '{{$urls->api}}/search/ventas'
|
||||
const chunks = []
|
||||
for (let i = 0; i < this.queues.ventas.length; i += 100) {
|
||||
chunks.push(this.queues.ventas.slice(i, i + 100))
|
||||
}
|
||||
const promises = []
|
||||
chunks.forEach(ids => {
|
||||
const body = new FormData()
|
||||
body.set('ventas', ids)
|
||||
promises.push(fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json()
|
||||
}))
|
||||
})
|
||||
return Promise.all(promises)
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -309,15 +333,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
set: function() {
|
||||
return {
|
||||
query: value => {
|
||||
$("[name='query']").val(value)
|
||||
this.get().results()
|
||||
}
|
||||
}
|
||||
},
|
||||
setup: function(id) {
|
||||
this.id = id
|
||||
this.get().results()
|
||||
|
||||
$('#tipo').dropdown().dropdown('set selected', '*')
|
||||
@if (trim($post) !== '')
|
||||
$("[name='query']").val('{{$post}}')
|
||||
this.set().query('{!! $post !!}')
|
||||
@elseif (trim($query) !== '')
|
||||
$("[name='query']").val('{{$query}}')
|
||||
this.set().query('{!! $query !!}')
|
||||
@endif
|
||||
@if (trim($tipo) !== '')
|
||||
$('#tipo').dropdown('set selected', '{{$tipo}}')
|
||||
|
@ -349,7 +349,7 @@
|
||||
const lines = [
|
||||
'<label for="rut">RUT</label>',
|
||||
'<div class="inline field">',
|
||||
'<input type="text" id="rut" name="rut" />',
|
||||
'<input type="text" id="rut" name="rut" placeholder="00000000-0" />',
|
||||
'<span class="ui error message" id="alert_rut">',
|
||||
'<i class="exclamation triangle icon"></i>',
|
||||
'RUT Inválido',
|
||||
@ -358,25 +358,25 @@
|
||||
'<label for="nombres">Nombre</label>',
|
||||
'<div class="inline fields">',
|
||||
'<div class="field">',
|
||||
'<input type="text" name="nombres" id="nombres" />',
|
||||
'<input type="text" name="nombres" id="nombres" placeholder="Nombre(s)" />',
|
||||
'</div>',
|
||||
'<div class="field">',
|
||||
'<input type="text" name="apellido_paterno" />',
|
||||
'<input type="text" name="apellido_paterno" placeholder="Apellido Paterno" />',
|
||||
'</div>',
|
||||
'<div class="field">',
|
||||
'<input type="text" name="apellido_materno" />',
|
||||
'<input type="text" name="apellido_materno" placeholder="Apellido Materno" />',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<label for="calle">Dirección</label>',
|
||||
'<div class="inline fields">',
|
||||
'<div class="eight wide field">',
|
||||
'<input type="text" name="calle" id="calle" size="16" />',
|
||||
'<input type="text" name="calle" id="calle" size="16" placeholder="Calle" />',
|
||||
'</div>',
|
||||
'<div class="field">',
|
||||
'<input type="text" name="numero" size="5" />',
|
||||
'<input type="text" name="numero" size="5" placeholder="Número" />',
|
||||
'</div>',
|
||||
'<div class="field">',
|
||||
'<input type="text" name="extra" />',
|
||||
'<input type="text" name="extra" placeholder="Otros Detalles" />',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="inline fields">',
|
||||
@ -789,6 +789,9 @@
|
||||
|
||||
$('#add_form').submit(event => {
|
||||
event.preventDefault()
|
||||
const button = $(event.currentTarget).find(".ui.button[type='submit']")
|
||||
button.prop('disabled', true)
|
||||
button.css('cursor', 'wait')
|
||||
const body = new FormData(event.currentTarget)
|
||||
const uri = '{{$urls->api}}/ventas/add'
|
||||
return fetchAPI(uri, {method: 'post', body}).then(response => {
|
||||
@ -800,6 +803,8 @@
|
||||
window.location = '{{$urls->base}}/venta/' + data.venta_id
|
||||
return true
|
||||
}
|
||||
button.prop('disabled', false)
|
||||
button.css('cursor', 'pointer')
|
||||
showErrors(data.errors)
|
||||
return false
|
||||
})
|
||||
|
294
app/resources/views/ventas/creditos.blade.php
Normal file
294
app/resources/views/ventas/creditos.blade.php
Normal file
@ -0,0 +1,294 @@
|
||||
@extends('ventas.base')
|
||||
|
||||
@section('venta_subtitle')
|
||||
Crédito
|
||||
@endsection
|
||||
|
||||
@section('venta_content')
|
||||
@php($credito = $venta->formaPago()->credito)
|
||||
<div class="ui grid">
|
||||
<div class="row">
|
||||
<div class="two wide column">Fecha</div>
|
||||
<div class="six wide column" id="fecha" data-status="static">
|
||||
<span id="fecha_data">
|
||||
{{$credito->pago->fecha->format('d-m-Y')}}
|
||||
</span>
|
||||
<a href="#" id="fecha_edit">
|
||||
<i class="edit icon"></i>
|
||||
</a>
|
||||
<div class="ui calendar hidden" id="fecha_input">
|
||||
<div class="ui left icon input">
|
||||
<i class="calendar icon"></i>
|
||||
<input type="text" name="fecha" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="two wide column">Banco</div>
|
||||
<div class="six wide column" id="banco" data-status="static">
|
||||
<span id="banco_data">
|
||||
@if (isset($credito->pago->banco))
|
||||
{{$credito->pago->banco->nombre}}
|
||||
@else
|
||||
No definido
|
||||
@endif
|
||||
</span>
|
||||
<a href="#" id="banco_edit">
|
||||
<i class="edit icon"></i>
|
||||
</a>
|
||||
<div class="ui search selection dropdown hidden" id="banco_input">
|
||||
<input type="hidden" name="banco" />
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="default text">Banco</div>
|
||||
<div class="menu">
|
||||
@foreach ($bancos as $banco)
|
||||
<div class="item" data-value="{{$banco->id}}">{{$banco->nombre}}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="two wide column">Valor</div>
|
||||
<div class="six wide column" id="valor" data-status="static">
|
||||
<span id="valor_data">
|
||||
{{$format->ufs($credito->pago->valor())}}
|
||||
</span>
|
||||
<a href="#" id="valor_edit">
|
||||
<i class="edit icon"></i>
|
||||
</a>
|
||||
<div class="ui right labeled input hidden" id="valor_input">
|
||||
<input type="text" name="valor" />
|
||||
<div class="ui basic label">UF</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('page_styles')
|
||||
<style>
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
const credito = {
|
||||
ids: {},
|
||||
data: {
|
||||
venta: {{$venta->id}},
|
||||
credito: {{$credito->id}},
|
||||
fecha: new Date({{$credito->pago->fecha->format('Y')}},
|
||||
{{$credito->pago->fecha->format('m')}}+1,
|
||||
{{$credito->pago->fecha->format('d')}}),
|
||||
banco: {
|
||||
@if (isset($credito->pago->banco))
|
||||
id: {{$credito->pago->banco->id}},
|
||||
nombre: '{{$credito->pago->banco->nombre}}'
|
||||
@else
|
||||
id: 0,
|
||||
nombre: ''
|
||||
@endif
|
||||
},
|
||||
valor: {{$credito->pago->valor()}},
|
||||
bancos: JSON.parse('{!! json_encode($bancos) !!}')
|
||||
},
|
||||
elements: {},
|
||||
change() {
|
||||
return {
|
||||
status: (id, status) => {
|
||||
this.elements[id].dataset.status = status
|
||||
}
|
||||
}
|
||||
},
|
||||
hide() {
|
||||
return {
|
||||
data: id => {
|
||||
this.elements[id + '.data'].innerHTML = ''
|
||||
this.elements[id + '.data'].classList.add('hidden')
|
||||
this.elements[id + '.data'].hidden = true
|
||||
},
|
||||
input: id => {
|
||||
this.elements[id + '.input'].classList.add('hidden')
|
||||
this.elements[id + '.input'].hidden = true
|
||||
}
|
||||
}
|
||||
},
|
||||
show() {
|
||||
return {
|
||||
data: id => {
|
||||
this.elements[id + '.data'].classList.remove('hidden')
|
||||
this.elements[id + '.data'].hidden = false
|
||||
},
|
||||
input: id => {
|
||||
this.elements[id + '.input'].classList.remove('hidden')
|
||||
this.elements[id + '.input'].hidden = false
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
return {
|
||||
edit: (id) => {
|
||||
this.change().status(id, 'edit')
|
||||
this.show().input(id)
|
||||
this.update()[id]()
|
||||
},
|
||||
static: (id, text) => {
|
||||
this.change().status(id, 'static')
|
||||
this.hide().input(id)
|
||||
this.elements[this.ids.fields[id] + '.data'].innerHTML = this.format()[id](text)
|
||||
}
|
||||
}
|
||||
},
|
||||
send(id, value) {
|
||||
const url = '{{$urls->api}}/venta/{{$venta->id}}/credito'
|
||||
const body = new FormData()
|
||||
body.set(id, value)
|
||||
return fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (!json.status) {
|
||||
return
|
||||
}
|
||||
this.data.fecha = new Date(json.credito.pago.fecha)
|
||||
this.data.banco.id = json.credito.pago.banco.id
|
||||
this.data.banco.nombre = json.credito.pago.banco.nombre
|
||||
this.data.valor = json.credito.pago.valor / json.credito.pago.uf
|
||||
})
|
||||
})
|
||||
},
|
||||
edit() {
|
||||
return {
|
||||
fecha: fecha => {
|
||||
this.send('fecha', fecha).then(() => {
|
||||
this.draw().static('fecha', this.data.fecha)
|
||||
})
|
||||
},
|
||||
banco: banco_id => {
|
||||
this.send('banco', banco_id).then(() => {
|
||||
this.draw().static('banco', this.data.banco.nombre)
|
||||
})
|
||||
},
|
||||
valor: valor => {
|
||||
this.send('valor', valor).then(() => {
|
||||
this.draw().static('valor', this.data.valor)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
format() {
|
||||
return {
|
||||
fecha: value => {
|
||||
const dateFormatter = new Intl.DateTimeFormat('es-CL', {year: 'numeric', month: 'numeric', day: 'numeric'})
|
||||
return dateFormatter.format(value)
|
||||
},
|
||||
banco: value => {
|
||||
if (value === '') {
|
||||
value = 'No definido'
|
||||
}
|
||||
return value
|
||||
},
|
||||
valor: value => {
|
||||
const numberFormatter = new Intl.NumberFormat('es-CL', {minimumFractionDigits: 2, maximumFractionDigits: 2})
|
||||
return numberFormatter.format(value) + ' UF'
|
||||
}
|
||||
}
|
||||
},
|
||||
update() {
|
||||
return {
|
||||
fecha: () => {
|
||||
const $fecha = $(this.elements.fecha.querySelector('div.ui.calendar'))
|
||||
$fecha.calendar('set date', this.data.fecha)
|
||||
$fecha.calendar('focus')
|
||||
},
|
||||
banco: () => {
|
||||
const $dropdown = $(this.elements.banco.querySelector('div.ui.dropdown'))
|
||||
$dropdown.dropdown('clear')
|
||||
if (this.data.banco.id !== 0) {
|
||||
$dropdown.dropdown('set selected', this.data.banco.id)
|
||||
}
|
||||
$dropdown.dropdown('toggle')
|
||||
},
|
||||
valor: () => {
|
||||
const input = this.elements.valor.querySelector('input')
|
||||
input.value = this.data.valor ?? ''
|
||||
input.focus()
|
||||
}
|
||||
}
|
||||
},
|
||||
watch(id) {
|
||||
this.elements[id + '.edit'].addEventListener('click', event => {
|
||||
const elem = event.currentTarget.parentNode
|
||||
const id = elem.id
|
||||
const status = elem.dataset.status
|
||||
if (status !== 'static') {
|
||||
return
|
||||
}
|
||||
this.draw().edit(id)
|
||||
})
|
||||
},
|
||||
register(name, elem_id) {
|
||||
this.elements[name] = document.getElementById(elem_id)
|
||||
},
|
||||
setup(ids) {
|
||||
this.ids = ids
|
||||
|
||||
Object.entries(this.ids.fields).forEach(entry => {
|
||||
const name = entry[0]
|
||||
const field = entry[1]
|
||||
this.register(name, field)
|
||||
this.register(name + '.data', field + '_data')
|
||||
this.register(name + '.input', field + '_input')
|
||||
this.register(name + '.edit', field + '_edit')
|
||||
this.watch(field)
|
||||
})
|
||||
calendar_date_options['onChange'] = (date, text, mode) => {
|
||||
if (date === this.data.fecha) {
|
||||
return
|
||||
}
|
||||
this.edit().fecha([date.getFullYear(), date.getMonth()+1, date.getDate()].join('-'))
|
||||
}
|
||||
calendar_date_options['onHide'] = () => {
|
||||
this.draw().static('fecha', this.data.fecha)
|
||||
}
|
||||
$(this.elements.fecha).find('div.ui.calendar').calendar(calendar_date_options)
|
||||
$(this.elements.banco).find('div.ui.dropdown').dropdown({
|
||||
onChange: (value, text, $element) => {
|
||||
if (value === '' || value === this.data.banco.id) {
|
||||
return
|
||||
}
|
||||
this.edit().banco(value)
|
||||
},
|
||||
onHide: () => {
|
||||
this.draw().static('banco', this.data.banco.nombre)
|
||||
}
|
||||
})
|
||||
this.elements.valor.querySelector('input').addEventListener('blur', event => {
|
||||
let valor = event.currentTarget.value
|
||||
if (valor.includes(',')) {
|
||||
valor = valor.replaceAll('.', '').replace(',', '.')
|
||||
}
|
||||
if (parseFloat(valor) === this.data.valor) {
|
||||
this.draw().static('valor', this.data.valor)
|
||||
return
|
||||
}
|
||||
this.edit().valor(valor)
|
||||
})
|
||||
}
|
||||
}
|
||||
$(document).ready(() => {
|
||||
credito.setup({
|
||||
fields: {
|
||||
fecha: 'fecha',
|
||||
banco: 'banco',
|
||||
valor: 'valor'
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
153
app/resources/views/ventas/escrituras/add.blade.php
Normal file
153
app/resources/views/ventas/escrituras/add.blade.php
Normal file
@ -0,0 +1,153 @@
|
||||
@extends('ventas.base')
|
||||
|
||||
@section('venta_subtitle')
|
||||
Agregar Abono en Escritura
|
||||
@endsection
|
||||
|
||||
@section('venta_content')
|
||||
<div class="ui basic segment">
|
||||
<p>Valor Promesa {{$format->ufs($venta->valor)}}</p>
|
||||
@if (isset($venta->formaPago()->pie))
|
||||
<p>Valor Anticipo {{$format->ufs($venta->formaPago()->pie->valor)}}</p>
|
||||
@endif
|
||||
@if (isset($venta->formaPago()->credito))
|
||||
<p>Crédito {{$format->ufs($venta->formaPago()->credito->pago->valor())}}</p>
|
||||
@endif
|
||||
</div>
|
||||
<form class="ui form" id="add_form">
|
||||
<div class="three wide field">
|
||||
<label for="fecha">Fecha</label>
|
||||
<div class="ui calendar" id="fecha">
|
||||
<div class="ui left icon input">
|
||||
<i class="calendar icon"></i>
|
||||
<input type="text" name="fecha" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label for="valor">Valor</label>
|
||||
<div class="ui labeled input" id="valor">
|
||||
<div class="ui basic label">$</div>
|
||||
<input type="text" name="valor" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox" id="uf">
|
||||
<input type="checkbox" name="uf" />
|
||||
<label>Valor en UFs</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fields">
|
||||
<div class="three wide field">
|
||||
<label for="bancos">Banco</label>
|
||||
<div class="ui search selection dropdown" id="bancos">
|
||||
<input type="hidden" name="banco" />
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="default text">Banco</div>
|
||||
<div class="menu">
|
||||
@foreach ($bancos as $banco)
|
||||
<div class="item" data-value="{{$banco->id}}">{{$banco->nombre}}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="tipo" value="1" checked="checked" />
|
||||
<label>Cheque</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="tipo" value="3" />
|
||||
<label>Vale Vista</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button">Agregar</button>
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
const escritura = {
|
||||
ids: {},
|
||||
add() {
|
||||
return {
|
||||
escritura: event => {
|
||||
event.preventDefault()
|
||||
const body = new FormData(event.currentTarget)
|
||||
const fecha = $(this.ids.fecha).calendar('get date')
|
||||
body.set('fecha', [fecha.getFullYear(), fecha.getMonth()+1, fecha.getDate()].join('-'))
|
||||
const status = $(this.ids.checkbox).checkbox('is checked')
|
||||
body.set('uf', status)
|
||||
|
||||
const url = '{{$urls->api}}/venta/{{$venta->id}}/escritura/add'
|
||||
fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
if (json.status) {
|
||||
window.location = '{{$urls->base}}/venta/{{$venta->id}}'
|
||||
}
|
||||
})
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
toggle() {
|
||||
return {
|
||||
checkbox: () => {
|
||||
const status = $(this.ids.checkbox).checkbox('is checked')
|
||||
if (status) {
|
||||
return this.toggle().uf()
|
||||
}
|
||||
return this.toggle().pesos()
|
||||
},
|
||||
uf: () => {
|
||||
const valor = $(this.ids.valor)
|
||||
valor.attr('class', 'ui right labeled input')
|
||||
valor.find('.label').remove()
|
||||
valor.append(
|
||||
$('<div></div>').addClass('ui basic label').html('UF')
|
||||
)
|
||||
},
|
||||
pesos: () => {
|
||||
const valor = $(this.ids.valor)
|
||||
valor.attr('class', 'ui labeled input')
|
||||
valor.find('.label').remove()
|
||||
valor.prepend(
|
||||
$('<div></div>').addClass('ui basic label').html('$')
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(ids) {
|
||||
this.ids = ids
|
||||
|
||||
$(this.ids.fecha).calendar(calendar_date_options)
|
||||
$(this.ids.checkbox).checkbox({
|
||||
fireOnInit: true,
|
||||
onChange: this.toggle().checkbox
|
||||
})
|
||||
$(this.ids.bancos).dropdown()
|
||||
$(this.ids.form).submit(this.add().escritura)
|
||||
}
|
||||
}
|
||||
$(document).ready(() => {
|
||||
escritura.setup({
|
||||
form: '#add_form',
|
||||
fecha: '#fecha',
|
||||
checkbox: '#uf',
|
||||
valor: '#valor',
|
||||
bancos: '#bancos'
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@ -1,5 +1,14 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@push('page_styles')
|
||||
<style>
|
||||
#data {
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('page_content')
|
||||
<div class="ui container">
|
||||
<h2 class="ui header">Matriz Facturación</h2>
|
||||
@ -24,7 +33,7 @@
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<table class="ui table" id="data"></table>
|
||||
<div id="data"></div>
|
||||
@endsection
|
||||
|
||||
@include('layout.head.styles.datatables')
|
||||
@ -33,53 +42,150 @@
|
||||
@push('page_scripts')
|
||||
<script>
|
||||
const money = {
|
||||
data: {
|
||||
ufs: {},
|
||||
ipcs: {}
|
||||
},
|
||||
ufs: {},
|
||||
ipcs: {},
|
||||
sent: {
|
||||
uf: {},
|
||||
ipc: {}
|
||||
},
|
||||
queue: {
|
||||
size: 0,
|
||||
array: () => {
|
||||
const array = []
|
||||
Object.entries(money.queue).forEach(([type, dates]) => {
|
||||
if (['uf', 'ipc'].includes(type) === false) {
|
||||
return
|
||||
}
|
||||
if (type === 'uf') {
|
||||
Object.entries(dates).forEach(([dateString, ventas]) => {
|
||||
const temp = []
|
||||
ventas.forEach(venta => {
|
||||
temp.push(venta)
|
||||
})
|
||||
array.push({
|
||||
type,
|
||||
date: dateString,
|
||||
ventas: temp
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
Object.entries(dates).forEach(([dateString, data]) => {
|
||||
const temp = []
|
||||
data.ventas.forEach(venta => {
|
||||
temp.push(venta)
|
||||
})
|
||||
array.push({
|
||||
type,
|
||||
start: data.start,
|
||||
end: data.end,
|
||||
ventas: temp
|
||||
})
|
||||
})
|
||||
})
|
||||
return array
|
||||
}
|
||||
},
|
||||
enqueue() {
|
||||
return {
|
||||
uf: ({date, venta_id}) => {
|
||||
const type = 'uf'
|
||||
const data = {
|
||||
date: [date.getFullYear(), date.getMonth()+1, date.getDate()].join('-'),
|
||||
}
|
||||
if (!(type in this.queue)) {
|
||||
this.queue[type] = {}
|
||||
}
|
||||
if (!(data.date in this.queue[type])) {
|
||||
this.queue[type][data.date] = []
|
||||
}
|
||||
if (this.queue[type][data.date].includes(data)) {
|
||||
return
|
||||
}
|
||||
this.queue[type][data.date].push(venta_id)
|
||||
this.queue['size'] ++
|
||||
},
|
||||
ipc: ({start, end, venta_id}) => {
|
||||
const type = 'ipc'
|
||||
let mult = 1
|
||||
if (start > end) {
|
||||
mult = -1
|
||||
let temp = end
|
||||
end = start
|
||||
start = temp
|
||||
}
|
||||
const data = {
|
||||
start: [start.getFullYear(), start.getMonth()+1, start.getDate()].join('-'),
|
||||
end: [end.getFullYear(), end.getMonth()+1, end.getDate()].join('-'),
|
||||
}
|
||||
if (!(type in this.queue)) {
|
||||
this.queue[type] = {}
|
||||
}
|
||||
if (!([data.start, data.end].join('|') in this.queue[type])) {
|
||||
this.queue[type][[data.start, data.end].join('|')] = {
|
||||
start: data.start,
|
||||
end: data.end,
|
||||
ventas: []
|
||||
}
|
||||
}
|
||||
if (this.queue[type][[data.start, data.end].join('|')].ventas.includes(data)) {
|
||||
return
|
||||
}
|
||||
this.queue[type][[data.start, data.end].join('|')].ventas.push({venta_id, mult})
|
||||
this.queue['size'] ++
|
||||
},
|
||||
}
|
||||
},
|
||||
get() {
|
||||
return {
|
||||
uf: date => {
|
||||
if (typeof this.sent.uf[date.toISOString()] !== 'undefined') {
|
||||
return this.sent.uf[date.toISOString()]
|
||||
many: () => {
|
||||
const url = '{{$urls->api}}/money/many'
|
||||
const method = 'post'
|
||||
const chunkSize = 100
|
||||
const promises = []
|
||||
for (let i = 0; i < this.queue.size; i += chunkSize) {
|
||||
const chunk = this.queue.array().slice(i, i + chunkSize)
|
||||
const missing = chunk.filter(data => {
|
||||
if (data.type === 'uf') {
|
||||
return !(data.date in this.data.ufs)
|
||||
}
|
||||
const url = '{{$urls->api}}/money/uf'
|
||||
const data = new FormData()
|
||||
data.set('fecha', date.toISOString())
|
||||
const options = {
|
||||
method: 'post',
|
||||
body: data
|
||||
if (data.type === 'ipc') {
|
||||
const dateKey = [data.start, data.end].join('|')
|
||||
return !(dateKey in this.data.ipcs)
|
||||
}
|
||||
return this.sent.uf[date.toISOString()] = fetchAPI(url, options).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
}).then(json => {
|
||||
return this.ufs[json.input.fecha] = json.uf
|
||||
})
|
||||
},
|
||||
ipc: (end, start) => {
|
||||
const dateKey = [start.getFullYear(), (start.getMonth()+1), end.getFullYear(), (end.getMonth()+1)].join('-')
|
||||
if (typeof this.sent.ipc[dateKey] !== 'undefined') {
|
||||
return this.sent.ipc[dateKey]
|
||||
if (missing.length === 0) {
|
||||
continue
|
||||
}
|
||||
const url = '{{$urls->api}}/money/ipc'
|
||||
const data = new FormData()
|
||||
data.set('start', start.toISOString())
|
||||
data.set('end', end.toISOString())
|
||||
const body = new FormData()
|
||||
body.set('dates', JSON.stringify(missing))
|
||||
const options = {
|
||||
method: 'post',
|
||||
body: data
|
||||
method,
|
||||
body
|
||||
}
|
||||
return this.sent.ipc[dateKey] = fetchAPI(url, options).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
promises.push(fetchAPI(url, options).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
json.values.forEach(data => {
|
||||
if (data.type === 'uf') {
|
||||
this.data.ufs[data.date] = data.value
|
||||
}
|
||||
if (data.type === 'ipc') {
|
||||
const dateKey = [data.start, data.end].join('|')
|
||||
this.data.ipcs[dateKey] = data.value
|
||||
}
|
||||
}).then(json => {
|
||||
return this.ipcs[json.date_string] = json.ipc
|
||||
})
|
||||
return json.values
|
||||
})
|
||||
}))
|
||||
}
|
||||
return Promise.all(promises)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,8 +198,7 @@
|
||||
prorrateo
|
||||
precio
|
||||
|
||||
constructor({id, tipo, descripcion, prorrateo, precio})
|
||||
{
|
||||
constructor({id, tipo, descripcion, prorrateo, precio}) {
|
||||
this.id = id
|
||||
this.tipo = tipo
|
||||
this.descripcion = descripcion
|
||||
@ -111,44 +216,13 @@
|
||||
unidades
|
||||
principal
|
||||
|
||||
constructor({id, precio, fecha, escritura}) {
|
||||
constructor({id, precio, fecha, escritura, unidades, principal}) {
|
||||
this.id = id
|
||||
this.precio = precio
|
||||
this.fecha = fecha
|
||||
this.escritura = escritura
|
||||
this.uf = 1
|
||||
this.ipc = 1
|
||||
this.unidades = []
|
||||
}
|
||||
|
||||
get() {
|
||||
return {
|
||||
unidades: () => {
|
||||
const url = '{{$urls->api}}/venta/' + this.id + '/unidades'
|
||||
return fetchAPI(url).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
}).then(json => {
|
||||
json.unidades.forEach(unidad => {
|
||||
const tipo = unidad.proyecto_tipo_unidad.tipo_unidad.descripcion
|
||||
const data = {
|
||||
id: unidad.id,
|
||||
tipo: tipo.charAt(0).toUpperCase() + tipo.slice(1),
|
||||
descripcion: unidad.descripcion,
|
||||
prorrateo: unidad.prorrateo,
|
||||
precio: 0
|
||||
}
|
||||
if (unidad.current_precio !== null) {
|
||||
data.precio = unidad.current_precio.valor
|
||||
}
|
||||
const u = new Unidad(data)
|
||||
this.unidades.push(u)
|
||||
})
|
||||
this.principal = this.unidades.filter(unidad => unidad.tipo === 'Departamento')[0]
|
||||
})
|
||||
}
|
||||
}
|
||||
this.fecha = new Date(fecha)
|
||||
this.escritura = new Date(escritura)
|
||||
this.unidades = unidades
|
||||
this.principal = principal
|
||||
}
|
||||
|
||||
draw({tbody, valor_terreno}) {
|
||||
@ -173,16 +247,17 @@
|
||||
const dateFormatter = new Intl.DateTimeFormat('es-CL', {year: 'numeric', month: 'numeric', day: 'numeric'})
|
||||
const pesosFormatter = new Intl.NumberFormat('es-CL', {style: 'currency', currency: 'CLP'})
|
||||
const ufFormatter = new Intl.NumberFormat('es-CL', {minimumFractionDigits: 2, maximumFractionDigits: 2})
|
||||
const venta = this.unidades[0].descripcion
|
||||
const venta = this.principal.descripcion
|
||||
const cantidad = this.unidades.length
|
||||
this.unidades.forEach(unidad => {
|
||||
const valor = (unidad.valor > 0) ? unidad.valor : unidad.precio
|
||||
const values = [
|
||||
venta,
|
||||
'<a href="{{$urls->base}}/ventas/factura/' + this.id + '">' + venta + '</a>',
|
||||
cantidad,
|
||||
unidad.tipo,
|
||||
unidad.descripcion,
|
||||
dateFormatter.format(this.fecha),
|
||||
ufFormatter.format(unidad.precio) + ' UF',
|
||||
ufFormatter.format(valor) + ' UF',
|
||||
unidad.prorrateo,
|
||||
'',
|
||||
'',
|
||||
@ -195,22 +270,23 @@
|
||||
''
|
||||
]
|
||||
if (this.escritura !== null) {
|
||||
const descuento = valor_terreno * (1 + this.ipc / 100) * unidad.prorrateo
|
||||
const precio_venta = unidad.precio * this.uf
|
||||
const ipc = (this.ipc >= 0) ? (1 + this.ipc) : 1 / (1 + this.ipc)
|
||||
const descuento = valor_terreno * ipc * unidad.prorrateo
|
||||
const precio_venta = valor * this.uf
|
||||
const precio_bruto = precio_venta - descuento
|
||||
const precio_neto = precio_bruto / 1.19
|
||||
const iva = precio_bruto - precio_neto
|
||||
|
||||
let i = 7
|
||||
values[i++] = pesosFormatter.format(descuento)
|
||||
values[i++] = pesosFormatter.format(precio_venta)
|
||||
values[i++] = pesosFormatter.format(precio_bruto)
|
||||
values[i++] = pesosFormatter.format(iva)
|
||||
values[i++] = pesosFormatter.format(precio_neto)
|
||||
values[i++] = (iva / precio_venta * 100).toFixed(2) + '%'
|
||||
values[i++] = (!isNaN(descuento)) ? pesosFormatter.format(descuento) : '<div class="ui active inline loader"></div>'
|
||||
values[i++] = (!isNaN(precio_venta)) ? pesosFormatter.format(precio_venta) : ''
|
||||
values[i++] = (!isNaN(precio_bruto)) ? pesosFormatter.format(precio_bruto) : ''
|
||||
values[i++] = (!isNaN(iva)) ? pesosFormatter.format(iva) : ''
|
||||
values[i++] = (!isNaN(precio_neto)) ? pesosFormatter.format(precio_neto) : ''
|
||||
values[i++] = (!isNaN(iva) && !isNaN(precio_venta)) ? (iva / precio_venta * 100).toFixed(2) + '%' : ''
|
||||
values[i++] = dateFormatter.format(this.escritura)
|
||||
values[i++] = ufFormatter.format(this.uf)
|
||||
values[i++] = (this.ipc).toFixed(2) + '%'
|
||||
values[i++] = (!isNaN(this.uf)) ? ufFormatter.format(this.uf) : ''
|
||||
values[i++] = (!isNaN(this.ipc)) ? (ufFormatter.format(this.ipc >= 0 ? this.ipc * 100 : -this.ipc * 100) + '%') : ''
|
||||
}
|
||||
const row = $('<tr></tr>')
|
||||
values.forEach(value => {
|
||||
@ -226,74 +302,144 @@
|
||||
ids: {},
|
||||
selected: 0,
|
||||
data: JSON.parse('{!! json_encode($proyectos) !!}'),
|
||||
sent: false,
|
||||
queues: {
|
||||
uf: {},
|
||||
ipc: {}
|
||||
},
|
||||
ufs: {},
|
||||
ipcs: {},
|
||||
table: null,
|
||||
get: function() {
|
||||
return {
|
||||
ventas: () => {
|
||||
const url = '{{$urls->api}}/ventas/facturacion/proyecto/' + this.selected
|
||||
return fetchAPI(url).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
if (this.sent) {
|
||||
return
|
||||
}
|
||||
}).then(json => {
|
||||
this.sent = true
|
||||
const url = '{{$urls->api}}/ventas/facturacion/proyecto/' + this.selected
|
||||
this.draw().loading()
|
||||
return fetchAPI(url).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(json => {
|
||||
const idx = this.data.findIndex(proyecto => proyecto.id === json.proyecto_id)
|
||||
const fecha_terreno = new Date(this.data[idx].terreno.date)
|
||||
this.data[idx]['ventas'] = []
|
||||
const ventas = []
|
||||
json.ventas.forEach(venta => {
|
||||
const data = {
|
||||
id: venta.id,
|
||||
precio: venta.valor,
|
||||
fecha: new Date(venta.fecha),
|
||||
escritura: null
|
||||
const chunkSize = 100
|
||||
for (let i = 0; i < json.ventas.length; i += chunkSize) {
|
||||
const chunk = json.ventas.slice(i, i + chunkSize).map(venta => venta.id)
|
||||
ventas.push(this.get().chunk({idx, chunk}))
|
||||
}
|
||||
if (['escriturando'].includes(venta.current_estado.tipo_estado_venta.descripcion)) {
|
||||
data.escritura = new Date(venta.current_estado.fecha)
|
||||
}
|
||||
const v = new Venta(data)
|
||||
const promises = []
|
||||
if (v.escritura !== null) {
|
||||
promises.push(money.get().uf(v.escritura).then(uf => {
|
||||
v.uf = uf
|
||||
}))
|
||||
promises.push(money.get().ipc(v.escritura, fecha_terreno).then(ipc => {
|
||||
v.ipc = ipc
|
||||
}))
|
||||
}
|
||||
promises.push(v.get().unidades())
|
||||
const promise = Promise.all(promises).then(() => {
|
||||
this.data[idx].ventas.push(v)
|
||||
})
|
||||
ventas.push(promise)
|
||||
})
|
||||
Promise.all(ventas).then(() => {
|
||||
this.data[idx].ventas.sort((a, b) => parseInt(a.principal.descripcion) - parseInt(b.principal.descripcion))
|
||||
this.draw().ventas(idx)
|
||||
this.sent = false
|
||||
money.get().many().then(response => {
|
||||
response.forEach(dates => {
|
||||
dates.forEach(values => {
|
||||
values.ventas.forEach(venta => {
|
||||
let vidx = 0
|
||||
if (values.type === 'uf') {
|
||||
vidx = this.data[idx].ventas.findIndex(v => v.id === venta)
|
||||
this.data[idx].ventas[vidx].uf = values.value
|
||||
return
|
||||
}
|
||||
if (values.type === 'ipc') {
|
||||
vidx = this.data[idx].ventas.findIndex(v => v.id === venta.venta_id)
|
||||
this.data[idx].ventas[vidx].ipc = values.value * venta.mult
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
this.draw().ventas(idx)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
chunk: ({idx, chunk}) => {
|
||||
const url = '{{$urls->api}}/ventas/facturacion/get'
|
||||
const method = 'post'
|
||||
const body = new FormData()
|
||||
body.set('ventas', chunk)
|
||||
|
||||
return fetchAPI(url, {method, body}).then(response => {
|
||||
if (!response) {
|
||||
return response
|
||||
}
|
||||
return response.json().then(json => {
|
||||
json.ventas.forEach(venta => {
|
||||
this.add().venta({proyecto_idx: idx, venta})
|
||||
})
|
||||
});
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
add() {
|
||||
return {
|
||||
venta: ({proyecto_idx, venta}) => {
|
||||
const v = new Venta(venta)
|
||||
this.data[proyecto_idx].ventas.push(v)
|
||||
const fecha_terreno = (typeof this.data[proyecto_idx].terreno.fecha === 'undefined') ? new Date() : new Date(this.data[proyecto_idx].terreno.fecha)
|
||||
|
||||
if (v.escritura !== null) {
|
||||
money.enqueue().uf({date: v.escritura, venta_id: v.id})
|
||||
money.enqueue().ipc({start: v.escritura, end: fecha_terreno, venta_id: v.id})
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
register() {
|
||||
return {
|
||||
uf: ({dateString, venta_id}) => {
|
||||
if (!Object.hasOwn(this.queues.uf, dateString)) {
|
||||
this.queues.uf[dateString] = []
|
||||
}
|
||||
this.queues.uf[dateString].push(venta_id)
|
||||
},
|
||||
ipc: ({dateString, venta_id}) => {
|
||||
if (!Object.hasOwn(this.queues.ipc, dateString)) {
|
||||
this.queues.ipc[dateString] = []
|
||||
}
|
||||
this.queues.ipc[dateString].push(venta_id)
|
||||
}
|
||||
}
|
||||
},
|
||||
draw: function() {
|
||||
return {
|
||||
proyectos: () => {
|
||||
$(this.ids.title).html('Proyectos')
|
||||
if (this.table !== null) {
|
||||
this.table.clear()
|
||||
this.table.destroy()
|
||||
$(this.ids.data).html('')
|
||||
}
|
||||
$(this.ids.data).hide()
|
||||
$(this.ids.proyectos).find('.item').css('cursor', 'pointer')
|
||||
$(this.ids.proyectos).show()
|
||||
},
|
||||
ventas: proyecto_idx => {
|
||||
const table = $(this.ids.data)
|
||||
$(this.ids.title).html(this.data[proyecto_idx].descripcion)
|
||||
const parent = $(this.ids.data)
|
||||
if (this.table !== null) {
|
||||
this.table.clear().destroy()
|
||||
this.table.clear()
|
||||
this.table.destroy()
|
||||
this.table = null
|
||||
parent.html('')
|
||||
}
|
||||
const table = $('<table></table>').addClass('ui compact table')
|
||||
table.append(this.draw().thead())
|
||||
table.append(this.draw().tbody(proyecto_idx))
|
||||
table.show()
|
||||
parent.show()
|
||||
parent.html(table)
|
||||
$(this.ids.proyectos).hide()
|
||||
if (this.table === null) {
|
||||
this.table = table.DataTable()
|
||||
const dtD = structuredClone(datatables_defaults)
|
||||
dtD['pageLength'] = 100
|
||||
dtD['order'] = [[0, 'asc']]
|
||||
this.table = table.DataTable(dtD)
|
||||
}
|
||||
},
|
||||
thead: () => {
|
||||
@ -331,6 +477,9 @@
|
||||
venta.draw({tbody, valor_terreno: this.data[proyecto_idx].terreno.valor})
|
||||
})
|
||||
return tbody
|
||||
},
|
||||
loading: () => {
|
||||
$(this.ids.proyectos).find('.item').css('cursor', 'wait')
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -369,6 +518,7 @@
|
||||
}
|
||||
$(document).ready(() => {
|
||||
proyectos.setup({ids: {
|
||||
title: '#list_title',
|
||||
proyectos: '#proyectos',
|
||||
data: '#data',
|
||||
buttons: {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -116,10 +116,15 @@
|
||||
this.data.id = data.proyecto.id
|
||||
this.data.proyecto = data.proyecto.descripcion
|
||||
this.data.venta_ids = data.ventas
|
||||
const chunkSize = 50
|
||||
const chunks = []
|
||||
for (let i = 0; i < data.ventas.length; i += chunkSize) {
|
||||
chunks.push(data.ventas.splice(i, i + chunkSize))
|
||||
}
|
||||
const promises = []
|
||||
data.ventas.forEach(venta_id => {
|
||||
const promise = this.get().venta(venta_id).then(() => {
|
||||
progress.progress('increment')
|
||||
chunks.forEach(chunk => {
|
||||
const promise = this.get().venta(chunk).then(count => {
|
||||
progress.progress('increment', count)
|
||||
})
|
||||
promises.push(promise)
|
||||
})
|
||||
@ -129,17 +134,22 @@
|
||||
}
|
||||
})
|
||||
},
|
||||
venta: venta_id => {
|
||||
return fetchAPI('{{$urls->api}}/venta/' + venta_id).then(response => {
|
||||
venta: chunk => {
|
||||
const body = new FormData()
|
||||
body.set('ventas', chunk.join(','))
|
||||
return fetchAPI('{{$urls->api}}/ventas/get', {method: 'post', body}).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
}).then(data => {
|
||||
if (typeof data.venta === 'undefined') {
|
||||
console.error(venta_id, data.error)
|
||||
if (data.ventas.length === 0) {
|
||||
console.error(chunk, data.error)
|
||||
return
|
||||
}
|
||||
this.add().venta(data.venta)
|
||||
data.ventas.forEach(venta_id => {
|
||||
this.add().venta(venta_id)
|
||||
})
|
||||
return data.ventas.length
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,30 @@
|
||||
@endsection
|
||||
|
||||
@section('venta_content')
|
||||
<table class="ui table" id="cuotas">
|
||||
@if (count($asociadas) > 0)
|
||||
<div class="ui grid">
|
||||
<div class="two wide column">Asociados</div>
|
||||
<div class="six wide column">
|
||||
{!! implode(' - ', array_map(function(Incoviba\Model\Venta $venta) use ($urls) {
|
||||
return "<a href=\"{$urls->base}/venta/{$venta->id}\">{$venta->propiedad()->departamentos()[0]->descripcion}</a>";
|
||||
}, $asociadas)) !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="ui grid">
|
||||
<div class="column">Valor</div>
|
||||
<div class="four wide column">
|
||||
{{$format->ufs($venta->formaPago()->pie->valor)}}
|
||||
@if (count($asociadas) > 0)
|
||||
[{{$format->ufs($venta->formaPago()->pie->valor + array_reduce($asociadas, function(float $sum, Incoviba\Model\Venta $venta) {
|
||||
return $sum + $venta->formaPago()->pie->valor;
|
||||
}, 0.0))}}]
|
||||
@endif
|
||||
</div>
|
||||
<div class="column">Cuotas</div>
|
||||
<div class="column">{{$venta->formaPago()->pie->cuotas}}</div>
|
||||
</div>
|
||||
<table class="ui compact table" id="cuotas">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
@ -37,32 +60,37 @@
|
||||
<td>{{$cuota->pago->identificador}}</td>
|
||||
<td class="right aligned">{{$format->pesos($cuota->pago->valor)}}</td>
|
||||
<td class="right aligned">
|
||||
@if ($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'abonado' and $cuota->pago->currentEstado->fecha <= $now)
|
||||
@if (in_array($cuota->pago->currentEstado->tipoEstadoPago->descripcion, ['depositado', 'abonado'])
|
||||
and $cuota->pago->currentEstado->fecha <= $now)
|
||||
{{$format->ufs($cuota->pago->valor())}}
|
||||
@else
|
||||
~{{$format->ufs($cuota->pago->valor / $uf_venta)}}
|
||||
@endif
|
||||
</td>
|
||||
<td
|
||||
@if ($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'abonado')
|
||||
class="green"
|
||||
@elseif ($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'depositado')
|
||||
class="yellow"
|
||||
@elseif ($cuota->pago->currentEstado->tipoEstadoPago->activo !== 1)
|
||||
class="red"
|
||||
@endif
|
||||
>{{ucwords($cuota->pago->currentEstado->tipoEstadoPago->descripcion)}}</td>
|
||||
<td{!! ($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'abonado' ? ' class="green"' :
|
||||
($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'depositado' ? ' class="yellow"' :
|
||||
($cuota->pago->currentEstado->tipoEstadoPago->activo !== 1 ? ' class="red"' : ''))) !!}>
|
||||
{{ucwords($cuota->pago->currentEstado->tipoEstadoPago->descripcion)}}
|
||||
</td>
|
||||
<td>
|
||||
@if (in_array($cuota->pago->currentEstado->tipoEstadoPago->descripcion, ['abonado', 'anulado', 'reemplazado']))
|
||||
{{$cuota->pago->currentEstado->fecha->format('d-m-Y')}}
|
||||
@elseif (!in_array($cuota->pago->currentEstado->tipoEstadoPago->descripcion, ['anulado', 'reemplazado']))
|
||||
@if ($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'depositado')
|
||||
{{$cuota->pago->currentEstado->fecha->format('d-m-Y')}}
|
||||
@endif
|
||||
<div class="ui calendar fecha_estado" data-date="{{$cuota->pago->currentEstado->fecha->format('Y-m-d')}}">
|
||||
<div class="ui action left icon input">
|
||||
<i class="calendar icon"></i>
|
||||
<input type="text" name="fecha_estado" />
|
||||
<button class="ui green basic icon button accept_estado" data-pago="{{$cuota->pago->id}}" data-estado="{{$cuota->pago->currentEstado->tipoEstadoPago->descripcion}}">
|
||||
<button class="ui green basic icon button accept_estado"
|
||||
data-pago="{{$cuota->pago->id}}"
|
||||
data-estado="{{$cuota->pago->currentEstado->tipoEstadoPago->descripcion}}">
|
||||
<i class="check icon"></i>
|
||||
</button>
|
||||
@if ($cuota->pago->currentEstado->tipoEstadoPago->descripcion === 'depositado')
|
||||
<button class="ui red basic icon button reject_estado" data-pago="{{$cuota->pago->id}}">
|
||||
<button class="ui red basic icon button reject_estado"
|
||||
data-pago="{{$cuota->pago->id}}">
|
||||
<i class="remove icon"></i>
|
||||
</button>
|
||||
@endif
|
||||
@ -115,7 +143,7 @@
|
||||
}, 0.0))}}
|
||||
</th>
|
||||
<th class="right aligned">
|
||||
{{$format->number($pagado / $total * 100, 2)}}%
|
||||
{{$format->number(($total > 0) ? $pagado / $total * 100 : 0, 2)}}%
|
||||
</th>
|
||||
<th colspan="3"></th>
|
||||
</tr>
|
||||
@ -128,7 +156,7 @@
|
||||
{{$format->ufs($total - $pagado)}}
|
||||
</th>
|
||||
<th class="right aligned">
|
||||
{{$format->number(($total - $pagado) / $total * 100, 2)}}%
|
||||
{{$format->number(($total > 0) ? ($total - $pagado) / $total * 100 : 0, 2)}}%
|
||||
</th>
|
||||
<th colspan="3"></th>
|
||||
</tr>
|
||||
@ -136,14 +164,18 @@
|
||||
</table>
|
||||
@endsection
|
||||
|
||||
@include('layout.head.styles.datatables')
|
||||
@include('layout.head.styles.datatables.buttons')
|
||||
@include('layout.body.scripts.datatables')
|
||||
@include('layout.body.scripts.datatables.buttons')
|
||||
|
||||
@push('page_scripts')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
function updateRow({pago_id, fecha, color, estado, remove_fecha=false, add_reject=false, disable=false}) {
|
||||
function updateRow({pago_id, valor, fecha, color, estado, remove_fecha=false, add_reject=false, disable=false}) {
|
||||
const tr = $("tr[data-pago='" + pago_id + "']")
|
||||
|
||||
tr.find(':nth-child(6)').html(valor)
|
||||
tr.find(':nth-child(7)').attr('class', color).html(estado)
|
||||
if (remove_fecha) {
|
||||
tr.find(':nth-child(8)').html(fecha)
|
||||
@ -178,7 +210,7 @@
|
||||
if (!json.depositado) {
|
||||
return
|
||||
}
|
||||
updateRow({pago_id: json.pago_id, fecha: json.input.fecha, estado: 'Depositado', color: 'yellow', add_reject: true})
|
||||
updateRow({pago_id: json.pago_id, valor: json.pago.valor_uf, fecha: json.input.fecha, estado: 'Depositado', color: 'yellow', add_reject: true})
|
||||
button.attr('data-estado', 'depositado')
|
||||
})
|
||||
})
|
||||
@ -186,7 +218,7 @@
|
||||
function abonar(pago_id, fecha) {
|
||||
const url = '{{$urls->api}}/ventas/pago/' + pago_id + '/abonar'
|
||||
const body = new FormData()
|
||||
body.set('fecha', fecha.toISOString())
|
||||
body.set('fecha', [fecha.getFullYear(), fecha.getMonth() + 1, fecha.getDate()].join('-'))
|
||||
return fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
@ -210,11 +242,6 @@
|
||||
return
|
||||
}
|
||||
updateRow({pago_id: json.pago_id, fecha: json.fecha, estado: 'Anulado', color: 'red', remove_fecha: true, disable: true})
|
||||
/*const tr = $("button[data-id='" + json.pago_id + "']").parent().parent()
|
||||
tr.addClass('disabled')
|
||||
tr.find(':nth-child(7)').addClass('red').html('Anulado')
|
||||
tr.find(':nth-child(8)').html(json.fecha)
|
||||
tr.find(':nth-child(9)').html('')*/
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -272,7 +299,7 @@
|
||||
zeroRecords: 'No se encotró cuotas con ese criterio',
|
||||
search: 'Buscar: '
|
||||
},
|
||||
pageLength: "25",
|
||||
pageLength: "100",
|
||||
columnDefs: [
|
||||
{
|
||||
target: 1,
|
||||
@ -296,7 +323,23 @@
|
||||
order: [
|
||||
[0, 'asc'],
|
||||
[2, 'asc']
|
||||
],
|
||||
layout: {
|
||||
top2End: {
|
||||
buttons: [
|
||||
{
|
||||
extend: 'excel',
|
||||
className: 'green',
|
||||
text: 'Exportar a Excel <i class="file excel icon"></i>',
|
||||
title: 'Cuotas - {{$venta->proyecto()->descripcion}} - {{$venta->propiedad()->summary()}}',
|
||||
download: 'open',
|
||||
exportOptions: {
|
||||
columns: ':visible'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
@ -81,7 +81,7 @@
|
||||
tipo_id: {{$unidad->proyectoTipoUnidad->tipoUnidad->id}},
|
||||
descripcion: '{{$unidad->descripcion}}',
|
||||
pid: {{$unidad->pu_id}},
|
||||
valor: {{($unidad->valor > 0) ? $unidad->valor : $unidad->precio($venta->fecha)->valor}}
|
||||
valor: {{($unidad->valor > 0) ? $unidad->valor : ($unidad->precio($venta->fecha)->valor ?? 0)}}
|
||||
},
|
||||
@endforeach
|
||||
],
|
||||
@ -108,9 +108,12 @@
|
||||
},
|
||||
doAddUnidad: function() {
|
||||
const url = '{{$urls->api}}/ventas/propiedades/unidades/add'
|
||||
const data = new FormData(document.getElementById('add_form'))
|
||||
data.set('propiedad', {{$propiedad->id}})
|
||||
return fetchAPI(url, {method: 'post', body: data}).then(response => {
|
||||
const body = new FormData(document.getElementById('add_form'))
|
||||
body.set('propiedad', {{$propiedad->id}})
|
||||
if (body.get('valor') === '') {
|
||||
body.set('valor', '0')
|
||||
}
|
||||
return fetchAPI(url, {method: 'post', body}).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
|
@ -9,9 +9,12 @@ Editar Propietario
|
||||
<h2 class="ui header">Editar Propietario</h2>
|
||||
<form class="ui form" id="edit_form">
|
||||
<input type="hidden" name="venta_id" value="{{$venta_id}}" />
|
||||
<div class="field">
|
||||
<div class="two wide field">
|
||||
<label for="rut">RUT</label>
|
||||
{{$propietario->rut()}}
|
||||
<div class="ui right labeled input" id="rut">
|
||||
<input type="text" name="rut" value="{{number_format($propietario->rut, 0, ',', '.')}}" />
|
||||
<div class="ui basic label">-<span id="digito">{{$propietario->dv}}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
@ -62,60 +65,261 @@ Editar Propietario
|
||||
|
||||
@push('page_scripts')
|
||||
<script type="text/javascript">
|
||||
function drawComunas({parent, comunas}) {
|
||||
parent.html('')
|
||||
comunas.forEach(comuna => {
|
||||
const option = $('<option></option>')
|
||||
option.attr('value', comuna.id).html(comuna.descripcion)
|
||||
if (comuna.id === {{$propietario->datos->direccion->comuna->id}}) {
|
||||
option.prop('selected', true)
|
||||
class Propietario {
|
||||
props
|
||||
constructor({rut, digito, nombres, apellidos: {paterno, materno}, direccion: {calle, numero, extra, comuna, region}}) {
|
||||
this.props = {
|
||||
rut,
|
||||
digito,
|
||||
nombres,
|
||||
apellidos: {
|
||||
paterno,
|
||||
materno
|
||||
},
|
||||
direccion: {
|
||||
calle,
|
||||
numero,
|
||||
extra,
|
||||
comuna,
|
||||
region
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
return {
|
||||
rut: rut => {
|
||||
this.props.rut = rut
|
||||
this.update().digito(Rut.digito(this.props.rut))
|
||||
},
|
||||
digito: digito => {
|
||||
this.props.digito = digito
|
||||
},
|
||||
nombres: nombres => {
|
||||
this.props.nombres = nombres
|
||||
},
|
||||
apellidos: () => {
|
||||
return {
|
||||
paterno: paterno => {
|
||||
this.props.apellidos.paterno = paterno
|
||||
},
|
||||
materno: materno => {
|
||||
this.props.apellidos.materno = materno
|
||||
}
|
||||
}
|
||||
},
|
||||
direccion: () => {
|
||||
return {
|
||||
calle: calle => {
|
||||
this.props.direccion.calle = calle
|
||||
},
|
||||
numero: numero => {
|
||||
this.props.direccion.numero = numero
|
||||
},
|
||||
extra: extra => {
|
||||
this.props.direccion.extra = extra
|
||||
},
|
||||
comuna: comuna => {
|
||||
this.props.direccion.comuna = comuna
|
||||
},
|
||||
region: region => {
|
||||
this.props.direccion.region = region
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
edit() {
|
||||
const uri = '{{$urls->api}}/venta/{{$venta_id}}/propietario/edit'
|
||||
const originales = {
|
||||
rut: '{{trim($propietario->rut)}}',
|
||||
nombres: '{{trim($propietario->nombres)}}',
|
||||
apellidos: {
|
||||
paterno: '{{trim($propietario->apellidos['paterno'])}}',
|
||||
materno: '{{trim($propietario->apellidos['materno'])}}'
|
||||
},
|
||||
direccion: {
|
||||
calle: '{{trim($propietario->datos->direccion->calle)}}',
|
||||
numero: '{{$propietario->datos->direccion->numero}}',
|
||||
extra: '{{trim($propietario->datos->direccion->extra)}}',
|
||||
comuna: '{{$propietario->datos->direccion->comuna->id}}'
|
||||
}
|
||||
}
|
||||
const data = {}
|
||||
const collator = new Intl.Collator('es')
|
||||
Object.entries(originales).forEach(([key, value]) => {
|
||||
if (key === 'apellidos') {
|
||||
Object.entries(value).forEach(([k, v]) => {
|
||||
const val = this.props[key][k]
|
||||
if (collator.compare(val, v) !== 0) {
|
||||
data[`apellido_${k}`] = val
|
||||
}
|
||||
parent.append(option)
|
||||
})
|
||||
parent.show()
|
||||
parent.dropdown()
|
||||
return
|
||||
}
|
||||
if (key === 'direccion') {
|
||||
let changed = false
|
||||
Object.entries(value).forEach(([k, v]) => {
|
||||
const val = this.props[key][k]
|
||||
if (collator.compare(val, v) !== 0) {
|
||||
changed = true
|
||||
data[k] = val
|
||||
}
|
||||
})
|
||||
if (changed) {
|
||||
Object.entries(value).forEach(([k, v]) => {
|
||||
if (k in data) {
|
||||
return
|
||||
}
|
||||
data[k] = this.props[key][k]
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
const val = this.props[key]
|
||||
if (collator.compare(val, value) !== 0) {
|
||||
data[key] = val
|
||||
}
|
||||
})
|
||||
if (Object.keys(data).length === 0) {
|
||||
// No changes
|
||||
propietario.redirect()
|
||||
return
|
||||
}
|
||||
if ('rut' in data) {
|
||||
data['dv'] = Rut.digito(data['rut'])
|
||||
}
|
||||
function findComunas(direccion) {
|
||||
const original_id = $("[name='comuna']").val()
|
||||
const uri = '{{$urls->api}}/direcciones/comunas/find'
|
||||
const data = {direccion}
|
||||
return fetchAPI(uri,
|
||||
{method: 'post', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data)}
|
||||
{method: 'put', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data)}
|
||||
).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
}).then(data => {
|
||||
if (data.total === 0) {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
const comuna_id = data.comunas[0].id
|
||||
if (comuna_id === original_id) {
|
||||
return
|
||||
return response.json().then(data => {
|
||||
if (data.edited) {
|
||||
propietario.redirect()
|
||||
}
|
||||
const parent = $('#comunas')
|
||||
parent.dropdown('set selected', comuna_id)
|
||||
})
|
||||
})
|
||||
}
|
||||
function getComunas(region_id) {
|
||||
const parent = $('#comunas')
|
||||
parent.hide()
|
||||
const uri = '{{$urls->api}}/direcciones/region/' + region_id + '/comunas'
|
||||
}
|
||||
class Region {
|
||||
props
|
||||
comunas
|
||||
|
||||
constructor({id, descripcion, selected = false}) {
|
||||
this.props = {
|
||||
id,
|
||||
descripcion,
|
||||
selected
|
||||
}
|
||||
this.comunas = []
|
||||
}
|
||||
get() {
|
||||
return {
|
||||
comunas: () => {
|
||||
if (this.comunas.length > 0) {
|
||||
return new Promise(resolve => resolve())
|
||||
}
|
||||
const uri = '{{$urls->api}}/direcciones/region/' + this.props.id + '/comunas'
|
||||
return fetchAPI(uri).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
}).then(data => {
|
||||
return response.json().then(data => {
|
||||
if (data.total === 0) {
|
||||
return
|
||||
}
|
||||
drawComunas({parent, comunas: data.comunas})
|
||||
this.comunas = data.comunas.map(comuna => {
|
||||
let selected = false
|
||||
if (comuna.id === {{$propietario->datos->direccion->comuna->id}}) {
|
||||
selected = true
|
||||
}
|
||||
return {
|
||||
id: comuna.id,
|
||||
descripcion: comuna.descripcion,
|
||||
selected
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
function redirect() {
|
||||
window.location = '{{$urls->base}}/venta/{{$venta_id}}'
|
||||
}
|
||||
function changeDireccion() {
|
||||
}
|
||||
}
|
||||
class Form {
|
||||
static submit(event) {
|
||||
event.preventDefault()
|
||||
propietario.props.data.edit()
|
||||
return false
|
||||
}
|
||||
}
|
||||
class Watcher {
|
||||
static rut() {
|
||||
const rut = $("[name='rut']")
|
||||
rut.on('input', EventHandler.rut().update)
|
||||
rut.on('blur', EventHandler.rut().change)
|
||||
}
|
||||
static nombres() {
|
||||
$("[name='nombres']").change(event => {
|
||||
propietario.props.data.update().nombres($(event.currentTarget).val())
|
||||
})
|
||||
}
|
||||
static apellidos() {
|
||||
const watched = [
|
||||
'apellido_paterno',
|
||||
'apellido_materno'
|
||||
]
|
||||
watched.forEach(name => {
|
||||
$("[name='" + name + "']").change(event => {
|
||||
const value = $(event.currentTarget).val()
|
||||
const key = name.split('_')[1]
|
||||
propietario.props.data.update().apellidos()[key](value)
|
||||
})
|
||||
})
|
||||
}
|
||||
static direccion() {
|
||||
const watched = [
|
||||
'calle',
|
||||
'numero',
|
||||
'extra'
|
||||
]
|
||||
watched.forEach(name => {
|
||||
$("[name='" + name + "']").change(EventHandler.direccion)
|
||||
})
|
||||
}
|
||||
static region() {
|
||||
$('#region').change(EventHandler.region)
|
||||
}
|
||||
static comuna() {
|
||||
$('#comunas').change(event => {
|
||||
const comuna_id = $(event.currentTarget).val()
|
||||
propietario.props.data.update().direccion().comuna(comuna_id)
|
||||
})
|
||||
}
|
||||
|
||||
static run() {
|
||||
Watcher.rut()
|
||||
Watcher.nombres()
|
||||
Watcher.apellidos()
|
||||
Watcher.direccion()
|
||||
Watcher.region()
|
||||
Watcher.comuna()
|
||||
}
|
||||
}
|
||||
class EventHandler {
|
||||
static region(event) {
|
||||
const region_id = $(event.currentTarget).val()
|
||||
propietario.props.regiones.forEach(region => {
|
||||
region.props.selected = false
|
||||
})
|
||||
const region = propietario.props.regiones.find(region => region.props.id === region_id)
|
||||
region.props.selected = true
|
||||
region.get().comunas().then(() => {
|
||||
propietario.draw().comunas()
|
||||
})
|
||||
}
|
||||
static direccion(event) {
|
||||
const names = [
|
||||
'calle',
|
||||
'numero',
|
||||
@ -129,98 +333,218 @@ Editar Propietario
|
||||
const values = []
|
||||
names.forEach(name => {
|
||||
const val = $("[name='" + name + "']").val()
|
||||
propietario.props.data.update().direccion()[name](val)
|
||||
values.push(val)
|
||||
})
|
||||
const collator = new Intl.Collator('es')
|
||||
if (collator.compare(originals.join(' '), values.join(' ')) !== 0) {
|
||||
findComunas(values.join(' ').trim())
|
||||
propietario.find().comuna(values.join(' ').trim())
|
||||
}
|
||||
}
|
||||
function watchChangeDireccion() {
|
||||
const watched = [
|
||||
'calle',
|
||||
'numero',
|
||||
'extra'
|
||||
]
|
||||
watched.forEach(name => {
|
||||
$("[name='" + name + "']").change(event => {
|
||||
changeDireccion()
|
||||
})
|
||||
})
|
||||
}
|
||||
function editPropietario() {
|
||||
const uri = '{{$urls->api}}/ventas/propietario/{{$propietario->rut}}'
|
||||
const names = [
|
||||
'nombres',
|
||||
'apellido_paterno',
|
||||
'apellido_materno'
|
||||
]
|
||||
const values = [
|
||||
'{{trim($propietario->nombres)}}',
|
||||
'{{trim($propietario->apellidos['paterno'])}}',
|
||||
'{{trim($propietario->apellidos['materno'])}}'
|
||||
]
|
||||
const direccion_names = [
|
||||
'calle',
|
||||
'numero',
|
||||
'extra',
|
||||
'comuna'
|
||||
]
|
||||
const direccion_values = [
|
||||
'{{trim($propietario->datos->direccion->calle)}}',
|
||||
'{{$propietario->datos->direccion->numero}}',
|
||||
'{{trim($propietario->datos->direccion->extra)}}',
|
||||
'{{$propietario->datos->direccion->comuna->id}}'
|
||||
]
|
||||
const data = {}
|
||||
const collator = new Intl.Collator('es')
|
||||
names.forEach((name, index) => {
|
||||
const val = $("[name='" + name + "']").val()
|
||||
if (collator.compare(val, values[index]) !== 0) {
|
||||
console.debug(name, val, values[index], collator.compare(val, values[index]))
|
||||
data[name] = val
|
||||
}
|
||||
})
|
||||
direccion_names.forEach((name, index) => {
|
||||
const val = $("[name='" + name + "']").val()
|
||||
if (collator.compare(val, direccion_values[index]) !== 0) {
|
||||
if (typeof data['direccion'] === 'undefined') {
|
||||
data['direccion'] = {}
|
||||
}
|
||||
console.debug(name, val, direccion_values[index])
|
||||
data['direccion'][name] = val
|
||||
}
|
||||
})
|
||||
if (Object.keys(data).length === 0) {
|
||||
redirect()
|
||||
static rut() {
|
||||
return {
|
||||
change: event => {
|
||||
const rut = $("[name='rut']").val().replace(/\D/g, '')
|
||||
if (rut.length < 7) {
|
||||
return
|
||||
}
|
||||
propietario.find().propietario(rut)
|
||||
},
|
||||
update: event => {
|
||||
const input = $("[name='rut']")
|
||||
const rut = input.val().replace(/\D/g, '')
|
||||
propietario.props.data.update().rut(rut)
|
||||
input.val(Rut.format(rut))
|
||||
$('#digito').html(propietario.props.data.props.digito)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class Rut {
|
||||
static format(rut) {
|
||||
return Intl.NumberFormat('es-CL', {maximumFractionDigits: 0}).format(rut)
|
||||
}
|
||||
static digito(rut) {
|
||||
const cleanRut = rut.replace(/\D/g, ''); // Removes non-digit characters more efficiently
|
||||
let sum = 0;
|
||||
const factors = [2, 3, 4, 5, 6, 7, 2, 3, 4, 5];
|
||||
for (let i = 0; i < cleanRut.length; i++) {
|
||||
const digit = parseInt(cleanRut[cleanRut.length - 1 - i], 10);
|
||||
sum += digit * factors[i % factors.length];
|
||||
}
|
||||
const dv = 11 - (sum % 11);
|
||||
return dv === 10 ? 'K' : dv === 11 ? '0' : dv.toString();
|
||||
}
|
||||
}
|
||||
const propietario = {
|
||||
props: {
|
||||
ids: {},
|
||||
data: {},
|
||||
regiones: [],
|
||||
},
|
||||
update() {
|
||||
return {
|
||||
propietario: () => {
|
||||
$("[name='rut']").val(Rut.format(this.props.data.props.rut))
|
||||
$('#digito').html(this.props.data.props.digito)
|
||||
$("[name='nombres']").val(this.props.data.props.nombres)
|
||||
$("[name='apellido_paterno']").val(this.props.data.props.apellidos.paterno)
|
||||
$("[name='apellido_materno']").val(this.props.data.props.apellidos.materno)
|
||||
$("[name='calle']").val(this.props.data.props.direccion.calle)
|
||||
$("[name='numero']").val(this.props.data.props.direccion.numero)
|
||||
$("[name='extra']").val(this.props.data.props.direccion.extra)
|
||||
$('#region').val(this.props.data.props.direccion.region)
|
||||
this.update().region()
|
||||
},
|
||||
region: () => {
|
||||
this.props.regiones.forEach(region => {
|
||||
region.props.selected = false
|
||||
})
|
||||
this.props.regiones.filter(region => region.props.id === this.props.data.props.direccion.region).forEach(region => {
|
||||
region.props.selected = true
|
||||
})
|
||||
const promises = []
|
||||
this.props.regiones.filter(region => region.props.selected).forEach(region => {
|
||||
promises.push(region.get().comunas())
|
||||
})
|
||||
Promise.all(promises).then(() => {
|
||||
this.draw().comunas()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
find() {
|
||||
return {
|
||||
propietario: rut => {
|
||||
const uri = '{{$urls->api}}/ventas/propietario/' + rut
|
||||
return fetchAPI(uri).then(response => {
|
||||
if (!response) {
|
||||
this.draw().reset()
|
||||
return
|
||||
}
|
||||
return response.json().then(data => {
|
||||
if (data.propietario === null) {
|
||||
this.draw().reset()
|
||||
return
|
||||
}
|
||||
this.props.data.update().nombres(data.propietario.nombres)
|
||||
this.props.data.update().apellidos().paterno(data.propietario.apellidos.paterno)
|
||||
this.props.data.update().apellidos().materno(data.propietario.apellidos.materno)
|
||||
this.props.data.update().direccion().calle(data.propietario.direccion.calle)
|
||||
this.props.data.update().direccion().numero(data.propietario.direccion.numero)
|
||||
this.props.data.update().direccion().extra(data.propietario.direccion.extra)
|
||||
this.props.data.update().direccion().comuna(data.propietario.direccion.comuna.id)
|
||||
this.props.data.update().direccion().region(data.propietario.direccion.comuna.provincia.region.id)
|
||||
this.update().propietario()
|
||||
})
|
||||
})
|
||||
},
|
||||
comuna: direccion => {
|
||||
const original_id = $("[name='comuna']").val()
|
||||
const uri = '{{$urls->api}}/direcciones/comunas/find'
|
||||
const data = {direccion}
|
||||
return fetchAPI(uri,
|
||||
{method: 'put', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data)}
|
||||
{method: 'post', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data)}
|
||||
).then(response => {
|
||||
if (response.ok) {
|
||||
redirect()
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(data => {
|
||||
if (data.total === 0) {
|
||||
return
|
||||
}
|
||||
const comuna_id = data.comunas[0].id
|
||||
if (comuna_id === original_id) {
|
||||
return
|
||||
}
|
||||
const parent = $('#comunas')
|
||||
parent.dropdown('set selected', comuna_id)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
return {
|
||||
comunas: () => {
|
||||
const parent = $(this.props.ids.comuna)
|
||||
parent.html('')
|
||||
const region_id = $(this.props.ids.region).val()
|
||||
const comunas = this.props.regiones.find(region => region.props.id === region_id).comunas
|
||||
comunas.forEach(comuna => {
|
||||
const option = $('<option></option>')
|
||||
option.attr('value', comuna.id).html(comuna.descripcion)
|
||||
if (parseInt(comuna.id) === parseInt(this.props.data.props.direccion.comuna)) {
|
||||
option.prop('selected', true)
|
||||
}
|
||||
parent.append(option)
|
||||
})
|
||||
parent.show()
|
||||
parent.dropdown()
|
||||
},
|
||||
reset: () => {
|
||||
$("[name='nombres']").val('')
|
||||
$("[name='apellido_paterno']").val('')
|
||||
$("[name='apellido_materno']").val('')
|
||||
$("[name='calle']").val('')
|
||||
$("[name='numero']").val('')
|
||||
$("[name='extra']").val('')
|
||||
}
|
||||
}
|
||||
},
|
||||
redirect() {
|
||||
window.location = '{{$urls->base}}/venta/{{$venta_id}}'
|
||||
},
|
||||
setup({ids, propietario}) {
|
||||
this.props.ids = ids
|
||||
this.props.data = propietario
|
||||
|
||||
$(this.props.ids.region).dropdown()
|
||||
$(this.props.ids.region).change(EventHandler.region)
|
||||
|
||||
$(this.props.ids.comuna).hide()
|
||||
$(this.props.ids.region).find('option').each((index, element) => {
|
||||
const id = $(element).val()
|
||||
const descripcion = $(element).text()
|
||||
const selected = $(element).prop('selected')
|
||||
this.props.regiones.push(new Region({id, descripcion, selected}))
|
||||
})
|
||||
this.update().region()
|
||||
|
||||
$(this.props.ids.forms.edit).submit(Form.submit)
|
||||
Watcher.run()
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(() => {
|
||||
const regiones = $("select[name='region']")
|
||||
regiones.dropdown()
|
||||
regiones.change(event => {
|
||||
const region_id = $(event.currentTarget).val()
|
||||
getComunas(region_id)
|
||||
propietario.setup({
|
||||
ids: {
|
||||
region: '#region',
|
||||
comuna: '#comunas',
|
||||
forms: {
|
||||
edit: '#edit_form'
|
||||
},
|
||||
buttons: {
|
||||
guardar: '#guardar_button'
|
||||
}
|
||||
},
|
||||
propietario: new Propietario({
|
||||
rut: '{{$propietario->rut}}',
|
||||
digito: '{{$propietario->dv}}',
|
||||
nombres: '{{$propietario->nombres}}',
|
||||
apellidos: {
|
||||
paterno: '{{$propietario->apellidos['paterno']}}',
|
||||
materno: '{{$propietario->apellidos['materno']}}'
|
||||
},
|
||||
direccion: {
|
||||
calle: '{{$propietario->datos->direccion->calle}}',
|
||||
numero: '{{$propietario->datos->direccion->numero}}',
|
||||
extra: '{{$propietario->datos->direccion->extra}}',
|
||||
comuna: '{{$propietario->datos->direccion->comuna->id}}',
|
||||
region: '{{$propietario->datos->direccion->comuna->provincia->region->id}}',
|
||||
}
|
||||
})
|
||||
$('#comunas').hide()
|
||||
getComunas({{$propietario->datos->direccion->comuna->provincia->region->id}})
|
||||
$('#edit_form').submit(event => {
|
||||
event.preventDefault()
|
||||
editPropietario({{$propietario->rut}})
|
||||
return false
|
||||
})
|
||||
$('#guardar_button').click(event => {
|
||||
editPropietario({{$propietario->rut}})
|
||||
})
|
||||
watchChangeDireccion()
|
||||
})
|
||||
</script>
|
||||
@endpush
|
||||
|
@ -32,46 +32,3 @@ $showPropietario = true;
|
||||
@include('ventas.show.comentarios')
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
{{--@section('page_content')
|
||||
<div class="ui container">
|
||||
<div class="ui two column grid">
|
||||
<h1 class="four wide column header">
|
||||
<div class="content">
|
||||
<div class="ui dividing sub header">{{$venta->proyecto()->descripcion}}</div>
|
||||
{{$venta->propiedad()->summary()}}
|
||||
</div>
|
||||
</h1>
|
||||
<div class="right floated column">
|
||||
@include('ventas.show.propietario')
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="ui fitted basic mini segment">
|
||||
@if ($venta->currentEstado()->tipoEstadoVenta->activa)
|
||||
<a href="{{$urls->base}}/venta/{{$venta->id}}/desistir">
|
||||
Desistir <i class="minus icon"></i>
|
||||
</a>
|
||||
<a href="{{$urls->base}}/venta/{{$venta->id}}/ceder">
|
||||
Ceder <i clasS="right chevron icon"></i>
|
||||
</a>
|
||||
@else
|
||||
<div class="ui red icon label">
|
||||
<i class="ban icon"></i>
|
||||
{{ucwords($venta->currentEstado()->tipoEstadoVenta->descripcion)}}
|
||||
(<a href="{{$urls->base}}/venta/{{$venta->id}}/desistida">
|
||||
{{$format->pesos($venta->resciliacion()->valor)}}
|
||||
</a>)
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<div class="ui segments">
|
||||
@include('ventas.show.propiedad')
|
||||
@include('ventas.show.detalle')
|
||||
@include('ventas.show.forma_pago', ['formaPago' => $venta->formaPago()])
|
||||
@include('ventas.show.escritura')
|
||||
@include('ventas.show.entrega')
|
||||
@include('ventas.show.comentarios')
|
||||
</div>
|
||||
</div>
|
||||
@endsection--}}
|
||||
|
@ -3,9 +3,9 @@
|
||||
COMENTARIOS
|
||||
</div>
|
||||
<div class="right aligned column">
|
||||
<a href="javascript: addComment()" style="color: inherit;">
|
||||
<button class="ui icon button" style="background: none; color: inherit; padding: 0;" id="add_comentario_button">
|
||||
<i class="plus icon"></i>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui segment">
|
||||
@ -13,37 +13,199 @@
|
||||
<tbody id="comentarios"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="ui modal" id="addComment">
|
||||
<div class="header">
|
||||
Agregar Comentario
|
||||
</div>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<div class="three wide field">
|
||||
<label>Fecha</label>
|
||||
<div class="ui calendar" id="fecha">
|
||||
<div class="ui icon input">
|
||||
<input type="text" placeholder="Fecha">
|
||||
<i class="calendar icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Comentario</label>
|
||||
<textarea id="comentario" rows="2"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<div class="ui black deny button">
|
||||
Cancelar
|
||||
</div>
|
||||
<div class="ui positive right labeled icon button">
|
||||
Agregar
|
||||
<i class="checkmark icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui modal" id="editComment">
|
||||
<div class="header">
|
||||
Edit Comentario
|
||||
</div>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<input type="hidden" name="id" />
|
||||
<div class="three wide field">
|
||||
<label>Fecha</label>
|
||||
<div class="ui calendar" id="fechaEdit">
|
||||
<div class="ui icon input">
|
||||
<input type="text" placeholder="Fecha">
|
||||
<i class="calendar icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Comentario</label>
|
||||
<textarea id="comentarioEdit" rows="2"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<div class="ui black deny button">
|
||||
Cancelar
|
||||
</div>
|
||||
<div class="ui positive right labeled icon button">
|
||||
Editar
|
||||
<i class="checkmark icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('page_scripts')
|
||||
<script type="text/javascript">
|
||||
class Comentario
|
||||
{
|
||||
class Comentario {
|
||||
id
|
||||
fecha
|
||||
texto
|
||||
|
||||
constructor({fecha, texto})
|
||||
constructor({id, fecha, texto})
|
||||
{
|
||||
this.id = id
|
||||
this.fecha = new Date(fecha + 'T00:00:00')
|
||||
this.texto = texto
|
||||
}
|
||||
draw(dateFormatter)
|
||||
{
|
||||
return $('<tr></tr>').append(
|
||||
$('<td></td>').html(dateFormatter.format(this.fecha))
|
||||
).append(
|
||||
$('<td></td>').html(this.texto)
|
||||
).append(
|
||||
$('<td></td>').addClass('right aligned').append(
|
||||
$('<a></a>').attr('href', 'javascript: removeComment();').append(
|
||||
$('<i></i>').addClass('minus icon')
|
||||
)
|
||||
)
|
||||
)
|
||||
return [
|
||||
'<tr>',
|
||||
`<td class="collapsing">${dateFormatter.format(this.fecha)}</td>`,
|
||||
`<td>${this.texto}</td>`,
|
||||
'<td class="right aligned">',
|
||||
`<button class="ui tiny tertiary icon button editComentario" data-id="${this.id}">`,
|
||||
'<i class="edit icon"></i>',
|
||||
'</button>',
|
||||
`<button class="ui tiny tertiary red icon button removeComentario" data-id="${this.id}">`,
|
||||
'<i class="minus icon"></i>',
|
||||
'</button>',
|
||||
'</td>',
|
||||
'</tr>'
|
||||
].join("\n")
|
||||
}
|
||||
}
|
||||
class AddModal {
|
||||
props
|
||||
constructor({id}) {
|
||||
this.props = {
|
||||
id
|
||||
}
|
||||
$(this.props.id).modal({
|
||||
onApprove: () => {
|
||||
this.approve()
|
||||
}
|
||||
})
|
||||
const cdo = structuredClone(calendar_date_options)
|
||||
$(this.props.id).find('.ui.calendar').calendar(cdo)
|
||||
this.hide()
|
||||
}
|
||||
approve() {
|
||||
const fecha = $(this.props.id).find('#fecha').calendar('get date')
|
||||
const fechaString = [fecha.getFullYear(), fecha.getMonth()+1, fecha.getDate()].join('-')
|
||||
const comentario = $(this.props.id).find('#comentario').val()
|
||||
const uri = '{{$urls->api}}/venta/{{$venta->id}}/comentarios/add'
|
||||
const body = new FormData()
|
||||
body.append('fecha', fechaString)
|
||||
body.append('texto', comentario)
|
||||
fetchAPI(uri, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(data => {
|
||||
if (data.added) {
|
||||
comentarios.comentarios.push(new Comentario(data.comentario))
|
||||
comentarios.draw().comentarios()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
show() {
|
||||
const modal = $(this.props.id)
|
||||
modal.find('form').trigger('reset')
|
||||
modal.modal('show')
|
||||
}
|
||||
hide() {
|
||||
const modal = $(this.props.id)
|
||||
modal.modal('hide')
|
||||
}
|
||||
}
|
||||
class EditModal {
|
||||
props
|
||||
constructor({id}) {
|
||||
this.props = {
|
||||
id
|
||||
}
|
||||
$(this.props.id).modal({
|
||||
onApprove: () => {
|
||||
this.approve()
|
||||
}
|
||||
})
|
||||
const cdo = structuredClone(calendar_date_options)
|
||||
$(this.props.id).find('.ui.calendar').calendar(cdo)
|
||||
this.hide()
|
||||
}
|
||||
approve() {
|
||||
const id = $(this.props.id).find("[name='id']").val()
|
||||
const fecha = $(this.props.id).find('#fechaEdit').calendar('get date')
|
||||
const fechaString = [fecha.getFullYear(), fecha.getMonth()+1, fecha.getDate()].join('-')
|
||||
const comentario = $(this.props.id).find('#comentarioEdit').val()
|
||||
const uri = `{{$urls->api}}/ventas/comentario/${id}/edit`
|
||||
const body = new FormData()
|
||||
body.append('fecha', fechaString)
|
||||
body.append('texto', comentario)
|
||||
fetchAPI(uri, {method: 'post', body}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(data => {
|
||||
if (data.edited) {
|
||||
const idx = comentarios.comentarios.findIndex(comentario => comentario.id === data.comentario_id)
|
||||
comentarios.comentarios[idx] = new Comentario(data.comentario)
|
||||
comentarios.draw().comentarios()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
show() {
|
||||
const modal = $(this.props.id)
|
||||
modal.modal('show')
|
||||
}
|
||||
hide() {
|
||||
const modal = $(this.props.id)
|
||||
modal.modal('hide')
|
||||
}
|
||||
}
|
||||
const comentarios = {
|
||||
comentarios: [],
|
||||
id: '',
|
||||
modals: {
|
||||
add: null,
|
||||
edit: null
|
||||
},
|
||||
fetch: function() {
|
||||
return {
|
||||
comentarios: () => {
|
||||
@ -60,6 +222,7 @@
|
||||
this.comentarios.push(new Comentario(settings))
|
||||
})
|
||||
this.draw().comentarios()
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -73,11 +236,41 @@
|
||||
this.comentarios.forEach(comentario => {
|
||||
body.append(comentario.draw(dateFormatter))
|
||||
})
|
||||
$('.editComentario').on('click', event => {
|
||||
const id = $(event.currentTarget).data('id')
|
||||
const comentario = this.comentarios.find(comentario => comentario.id === id)
|
||||
const modal = this.modals.edit
|
||||
const fecha = new Date(comentario.fecha)
|
||||
$(modal.props.id).find("[name='id']").val(id)
|
||||
$(modal.props.id).find('#fechaEdit').calendar('set date', fecha)
|
||||
$(modal.props.id).find('#comentarioEdit').val(comentario.texto)
|
||||
modal.show()
|
||||
})
|
||||
$('.removeComentario').click(event => {
|
||||
const id = $(event.currentTarget).data('id')
|
||||
const uri = `{{$urls->api}}/ventas/comentario/${id}/remove`
|
||||
fetchAPI(uri, {method: 'delete'}).then(response => {
|
||||
if (!response) {
|
||||
return
|
||||
}
|
||||
return response.json().then(data => {
|
||||
if (data.removed) {
|
||||
this.comentarios = this.comentarios.filter(comentario => comentario.id !== id)
|
||||
this.draw().comentarios()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
setup: function(id) {
|
||||
this.id = id
|
||||
this.modals.add = new AddModal({id: '#addComment'})
|
||||
this.modals.edit = new EditModal({id: '#editComment'})
|
||||
$('#add_comentario_button').click(() => {
|
||||
this.modals.add.show()
|
||||
})
|
||||
this.fetch().comentarios()
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
<tr>
|
||||
<td>{{$format->ufs($venta->valor)}}</td>
|
||||
<td>{{$format->ufs($venta->util())}}</td>
|
||||
<td>{{$format->number($venta->util() / $venta->propiedad()->vendible(), 2)}} UF/m²</td>
|
||||
<td>{{($venta->propiedad()->vendible() > 0) ? $format->number($venta->util() / $venta->propiedad()->vendible(), 2) : 0}} UF/m²</td>
|
||||
<td>0,00 UF (0,00%)</td>
|
||||
<td>
|
||||
{{$venta->fecha->format('d-m-Y')}}<br/>
|
||||
|
@ -3,14 +3,14 @@
|
||||
</div>
|
||||
<div class="ui segment">
|
||||
<table class="ui very basic fluid table">
|
||||
@include('ventas.show.forma_pago.pie', ['pie' => $formaPago->pie])
|
||||
@include('ventas.show.forma_pago.escritura', ['escritura' => $formaPago->escritura])
|
||||
@include('ventas.show.forma_pago.anticipo', ['anticipo' => ['uf' => $formaPago->anticipo(), 'pesos' => $formaPago->anticipo('pesos')]])
|
||||
@include('ventas.show.forma_pago.bono_pie', ['bonoPie' => $formaPago->bonoPie])
|
||||
@include('ventas.show.forma_pago.subsidio', ['subsidio' => $formaPago->subsidio])
|
||||
@include('ventas.show.forma_pago.credito', ['credito' => $formaPago->credito])
|
||||
@include('ventas.show.forma_pago.pie', ['pie' => $formaPago?->pie])
|
||||
@include('ventas.show.forma_pago.escritura', ['escritura' => $formaPago?->escritura])
|
||||
@include('ventas.show.forma_pago.anticipo', ['anticipo' => ['uf' => $formaPago?->anticipo(), 'pesos' => $formaPago?->anticipo('pesos')]])
|
||||
@include('ventas.show.forma_pago.bono_pie', ['bonoPie' => $formaPago?->bonoPie])
|
||||
@include('ventas.show.forma_pago.subsidio', ['subsidio' => $formaPago?->subsidio])
|
||||
@include('ventas.show.forma_pago.credito', ['credito' => $formaPago?->credito])
|
||||
@include('ventas.show.forma_pago.total')
|
||||
@include('ventas.show.forma_pago.devolucion', ['devolucion' => $formaPago->devolucion])
|
||||
@include('ventas.show.forma_pago.devolucion', ['devolucion' => $formaPago?->devolucion])
|
||||
</table>
|
||||
</div>
|
||||
<div id="pago_modal" class="ui modal">
|
||||
|
@ -16,7 +16,7 @@
|
||||
<a href="{{$urls->base}}/venta/{{$venta->id}}/pie/cuotas">
|
||||
<span data-tooltip="Pagadas">{{count($pie->cuotas(true))}}</span>/{{$pie->cuotas}}
|
||||
</a>
|
||||
@if (count($pie->cuotas()) < $pie->cuotas)
|
||||
@if (count($pie->cuotas(false, true)) < $pie->cuotas)
|
||||
<a href="{{$urls->base}}/ventas/pie/{{$pie->id}}/cuotas/add">
|
||||
<i class="plus icon"></i>
|
||||
</a>
|
||||
|
@ -50,7 +50,7 @@
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
@if ($unidad->proyectoTipoUnidad->tipoUnidad->descripcion === 'departamento')
|
||||
{{$format->number(($unidad->valor ?? $precio) / $unidad->proyectoTipoUnidad->vendible(), 2)}} UF/m²
|
||||
{{$format->number((($unidad->valor === null or $unidad->valor === 0.0) ? $precio : $unidad->valor) / $unidad->proyectoTipoUnidad->vendible(), 2)}} UF/m²
|
||||
@endif
|
||||
</td>
|
||||
<td class="center aligned">
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user