100 Commits
Author SHA1 Message Date
alireza-hassani 7fd27c4693 Update .gitea/workflows/publish.yml 2026-05-12 14:51:17 +00:00
alireza-hassani 7a6c81600f Add .gitea/workflows/publish.yml 2026-05-12 14:51:00 +00:00
ehsan.moradi eeb90fe49e fix delete item 2025-06-08 13:50:00 +03:30
ehsan.moradi 6f12cd4e69 get inputs with udi too 2025-06-08 12:18:18 +03:30
ehsan.moradi b8b6e46cf2 add roles 2025-05-28 12:53:53 +03:30
ehsan.moradi 122c7cdbda fix 2025-05-26 11:09:33 +03:30
ehsan.moradi 0977346b6e fix 2025-05-25 16:03:03 +03:30
ehsan.moradi 8f0b87c333 fix 2025-05-25 15:01:29 +03:30
ehsan.moradi a467b06ea7 fix 2025-05-25 14:43:24 +03:30
zeinab.ashrafi 316c5507ba feat : show item by udi 2025-05-13 12:15:47 +03:30
ehsan.moradi fa7df1e500 showUdi item 2025-05-13 11:51:57 +03:30
zeinab.ashrafi 9040310170 fix : responsive 2025-05-13 11:16:04 +03:30
zeinab.ashrafi 156c3fbeb6 Merge branch 'master' of ssh://git.meshkee.com:2222/cssd/cssd-back 2025-05-12 15:28:34 +03:30
zeinab.ashrafi a7a46a1fd3 fix : responsive 2025-05-12 15:18:44 +03:30
ehsan.moradi 4a3b8fe5c0 fix 2025-05-11 17:31:08 +03:30
ehsan.moradi 2e59726bce fix 2025-05-10 13:07:58 +03:30
ehsan.moradi 4c48b13646 add test_type_name to test result index 2025-05-10 12:44:16 +03:30
ehsan.moradi 7ce5e0262b fix verify password 2025-05-07 12:53:52 +03:30
saeid.khakbazan b7694a92a4 Update Dockerfile.nginx 2025-05-07 06:28:26 +00:00
ehsan.moradi 0bd017360c add package name filter to label index 2025-05-06 11:31:05 +03:30
ehsan.moradi bcba3b7a8d verify password change 2025-05-06 11:06:52 +03:30
ehsan.moradi dd85f7f5e2 change GetInputs api 2025-05-05 17:26:36 +03:30
ehsan.moradi 263ef246fd fix: verify password 2025-05-05 16:25:37 +03:30
zeinab.ashrafi 38ca9b3b84 fix : style 2025-05-05 13:22:29 +03:30
zeinab.ashrafi bea98bdd02 fix : try to display files in test result 2025-05-05 13:11:16 +03:30
ehsan.moradi 7a7ad062c6 fix verify password 2025-05-05 11:11:33 +03:30
ehsan.moradi 27cd2292fe cssd changes and fixes 2025-05-04 16:42:14 +03:30
zeinab.ashrafi fee688c183 fix : style and display data 2025-05-04 14:06:08 +03:30
ehsan.moradi 4eb2fa5107 fix 2025-05-03 10:50:38 +03:30
ehsan.moradi edb9e9fc8a fix 2025-05-01 21:11:46 +03:30
ehsan.moradi 8b30242419 fix 2025-05-01 20:48:17 +03:30
ehsan.moradi 97f63d1435 add rahyab notification service 2025-05-01 20:08:12 +03:30
ehsan.moradi 44be70f3ff add rahyab notification service 2025-05-01 19:34:25 +03:30
ehsan.moradi baeaed7c70 add rahyab notifcation service 2025-05-01 17:39:46 +03:30
ehsan.moradi b573d1bbed add rahyab notification service 2025-05-01 17:18:14 +03:30
ehsan.moradi 6d108e43c9 fix transfer item issue 2025-05-01 13:15:47 +03:30
ehsan.moradi 2b8ad33cb2 change export download way 2025-05-01 11:49:11 +03:30
ehsan.moradi 354992fe48 get sms info 2025-04-29 12:05:25 +03:30
ehsan.moradi b3f733cdd0 adding items for myPackage too 2025-04-28 11:38:02 +03:30
ehsan.moradi c03c1196ec adding media for item edit 2025-04-27 12:41:50 +03:30
ehsan.moradi be86f52ae7 Merge branch 'master' of https://git.meshkee.com/cssd/cssd-back 2025-04-27 11:44:25 +03:30
zeinab.ashrafiandehsan.moradi 200888482f feat : lightbox 2025-04-27 11:33:37 +03:30
ehsan.moradi 838ad7ca12 only return user's packages and items for supervisor and user role, and adding items field for package index 2025-04-27 11:30:27 +03:30
zeinab.ashrafi 3ec315bc09 feat : lightbox 2025-04-27 10:38:26 +03:30
zeinab.ashrafi d84a9a18c0 fix : test-result details image and barcode 2025-04-23 11:55:25 +03:30
ehsan.moradi 6b18d07b73 dev-env: changes for docker and seeders 2025-04-22 17:14:24 +03:30
zeinab.ashrafi 66812c5ed4 fix : image and udi in item details 2025-04-22 14:32:37 +03:30
ehsan.moradi ea46db84a0 Merge branch 'temp' 2025-04-21 15:07:48 +03:30
ehsan.moradi 1916fac447 dockerize cssd for developement 2025-04-21 15:03:48 +03:30
zeinab.ashrafi fd70c015f3 fix : style 2025-04-19 11:22:46 +03:30
Moradi 056160bca5 Merge branch 'master' of https://git.meshkee.com/cssd/cssd-back 2025-04-12 18:09:45 +03:30
Moradi a5136a341f I had forgotten to update item package_id 2025-04-12 18:09:27 +03:30
zeinab.ashrafi 47aab06e49 fix : remove logs 2025-04-10 13:00:14 +03:30
Moradi f9023086c9 items that belongs to a package cannot be transferred. 2025-04-09 14:02:13 +03:30
Moradi 6311e2af70 just change an operator but the difference was huge. (index items) 2025-04-09 13:37:33 +03:30
Moradi 4492db15cf add pagination to my packages 2025-04-09 13:15:11 +03:30
Moradi 62a353ef80 ... 2025-04-09 12:49:02 +03:30
Moradi bae730e402 small change in show package guest route. 2025-04-09 10:51:59 +03:30
Moradi 6c8054edac Merge branch 'master' of https://git.meshkee.com/cssd/cssd-back 2025-04-09 10:49:42 +03:30
Moradi ac19e51d28 add show package guest route and add null on delete to package_id column for items table just in case. 2025-04-09 10:49:21 +03:30
zeinab.ashrafi 9832fbe81a fix: logs 2025-04-09 10:02:04 +03:30
zeinab.ashrafi 24aa9fb7f2 fix : add logs 2025-04-09 09:52:44 +03:30
Moradi 4f25abbf36 Merge branch 'master' of https://git.meshkee.com/cssd/cssd-back 2025-04-08 16:57:22 +03:30
Moradi 6de8d2dbae items didn't attach to package because the input was different with the way controller method handles it. 2025-04-08 16:56:39 +03:30
Ashrafi 1bd5970a58 fix : front component 2025-04-03 12:16:54 +03:30
Moradi accf16c184 change default spatie guard name to api 2025-03-25 11:47:30 +03:30
Moradi 540f9a1d65 ineffective small change 2025-03-17 15:54:37 +03:30
Moradi 4a9010d2c7 change item delete policy 2025-03-16 12:27:35 +03:30
Moradi 76c9ec4c8f add show item route for guests. 2025-03-16 11:41:49 +03:30
Moradi f5e1ff198e register method assign user role with web guard (default) I change it to api guard. 2025-03-15 14:41:15 +03:30
zeinab.ashrafi abd611cdcf fix : try to fix vue part 2025-03-15 14:28:43 +03:30
Moradi 8a90d3bce4 fix the issue with getByMedicalCenter (commented the wrong code) 2025-03-15 13:55:18 +03:30
saeid.khakbazan af876a5e07 Update Dockerfile.nginx 2025-03-14 20:09:03 +00:00
saeid.khakbazan 06850ca736 Update Dockerfile.nginx 2025-03-14 20:01:49 +00:00
saeid.khakbazan 62fc5dc977 Update Dockerfile.nginx 2025-03-14 19:53:45 +00:00
saeid.khakbazan 8ee7bb56b7 Update Dockerfile.nginx 2025-03-14 19:39:37 +00:00
saeid.khakbazan b4d3134230 Update Dockerfile.nginx 2025-03-14 19:34:26 +00:00
saeid.khakbazan 322c080028 Update Dockerfile.nginx 2025-03-14 19:16:42 +00:00
Moradi 0d1b0360ac change the show item url 2025-03-13 14:13:59 +03:30
Moradi 1ee3585674 add where condition to getLabels query to get only enabled labels 2025-03-13 13:02:47 +03:30
Moradi 1d98af0113 add validation for enabled labels, rename enable (to enabled) in labels table, and update the enabled attribute of corresponding labels to false when cycle saved 2025-03-13 12:45:00 +03:30
Moradi 034000bcef fix the issue with the previous commit. event was called before the labels attached to a cycle. 2025-03-12 16:42:00 +03:30
ehsan 5fe7474227 remove the validation for cycle number in store label and add an eloquent event for updating cycle number when cycle is saved. 2025-03-12 11:57:11 +03:30
Moradi 71e493ec10 change StatusTypeEnum::SUSPENDING to StatusTypeEnum::PENDING 2025-03-11 13:54:56 +03:30
Moradi b0b6d700ba remove status approved condition from index items for users and fix the issue with validating store package request. 2025-03-11 13:34:55 +03:30
Moradi 2d1df25b0e packages index problem 2025-03-11 13:18:47 +03:30
Moradi 0170cb1258 remove the where condition for index items query and add enable column to labels table. 2025-03-11 12:21:36 +03:30
Moradi 8046611c01 Merge branch 'ehsan' 2025-03-08 16:31:27 +03:30
Moradi 9c9f40d06e a little changes in retrieve data based on roles. 2025-03-05 12:28:25 +03:30
saeid.khakbazan 32a477548e Update .drone.yml 2025-03-04 10:23:36 +00:00
Moradi 505c176dad change willaspace.com to meshkee.com globally. 2025-03-04 12:06:21 +03:30
Moradi e5253f7eda there was a misunderstanding for this part I fix it. and the issue is not from the backend I just add some validation to make doubly sure. 2025-03-01 12:37:51 +03:30
Moradi 96de1c2fbe add new rules for store and update package 2025-02-27 17:57:46 +03:30
Moradi 117a1cb160 forgot sth "user can create a package only from his items" 2025-02-27 14:51:17 +03:30
Moradi 9bf95438b7 fix issue "user can create a package only from his items" 2025-02-27 14:46:14 +03:30
Moradi a4392b74c9 Fix this issue "error when two same label is included" 2025-02-27 11:49:43 +03:30
ehsan 869e3e0c59 little change - env example and seeder 2025-02-20 19:05:24 +03:30
amir-ys da9f6dbee4 feat: add ping route 2025-02-19 00:08:12 +03:30
amir-ys 82b33e8a8f Merge remote-tracking branch 'origin/master' 2025-02-18 23:49:56 +03:30
amir-ys f4acfd7531 feat: add export for cycles 2024-12-14 00:56:08 +03:30
83 changed files with 6586 additions and 18063 deletions
+11 -18
View File
@@ -8,12 +8,12 @@ clone:
# npm config set _auth token add command
steps:
- name: clone
image: docker.willaspace.com/repository/docker-hosted/alpine/git
image: docker.meshkee.com/repository/docker-hosted/alpine/git
commands:
- git clone $DRONE_GIT_HTTP_URL .
- git checkout $DRONE_COMMIT
- name: Build docker image
image: docker.willaspace.com/repository/docker-hosted/plugins/docker
image: docker.meshkee.com/repository/docker-hosted/plugins/docker
environment:
REGISTRY_USER_NAME:
from_secret: registry_username
@@ -24,8 +24,8 @@ steps:
- latest
- ${DRONE_BUILD_NUMBER}
dockerfile: Dockerfile
registry: docker.willaspace.com
repo: docker.willaspace.com/repository/docker-hosted/external-projects/cssd-back
registry: docker.meshkee.com
repo: docker.meshkee.com/repository/docker-hosted/external-projects/cssd-back
build_args_from_env:
- REGISTRY_USER_NAME
- REGISTRY_PASSWORD
@@ -36,18 +36,16 @@ steps:
when:
branch:
- master
event:
- push
- name: Build docker nginx image
image: docker.willaspace.com/repository/docker-hosted/plugins/docker
image: docker.meshkee.com/repository/docker-hosted/plugins/docker
settings:
tags:
- nginx-latest
- nginx-${DRONE_BUILD_NUMBER}
dockerfile: Dockerfile.nginx
registry: docker.willaspace.com
repo: docker.willaspace.com/repository/docker-hosted/external-projects/cssd-back
registry: docker.meshkee.com
repo: docker.meshkee.com/repository/docker-hosted/external-projects/cssd-back
username:
from_secret: registry_username
password:
@@ -55,11 +53,9 @@ steps:
when:
branch:
- master
event:
- push
- name: deploy
image: docker.willaspace.com/repository/docker-hosted/pelotech/drone-helm3:latest
image: pelotech/drone-helm3:latest
environment:
USERNAME:
from_secret: registry_username
@@ -77,20 +73,17 @@ steps:
release: cssd-production-back
namespace: cssd
add_repos:
- willaspace=https://$USERNAME:$PASSWORD@repo.willaspace.com/repository/willaspace-charts/
- willaspace=https://$USERNAME:$PASSWORD@repo.meshkee.com/repository/willaspace-charts/
values_files:
- .values.yaml
values:
- deployment.image.tag=nginx-$DRONE_BUILD_NUMBER
- deployment.additionalContainers[0].image=docker.willaspace.com/repository/docker-hosted/external-projects/cssd-back:$DRONE_BUILD_NUMBER
- deployment.initContainers.init-artisan.image=docker.willaspace.com/repository/docker-hosted/external-projects/cssd-back:$DRONE_BUILD_NUMBER
- deployment.additionalContainers[0].image=docker.meshkee.com/repository/docker-hosted/external-projects/cssd-back:$DRONE_BUILD_NUMBER
- deployment.initContainers.init-artisan.image=docker.meshkee.com/repository/docker-hosted/external-projects/cssd-back:$DRONE_BUILD_NUMBER
timeout: 3000
when:
branch:
- master
event:
- pull_request
- push
image_pull_secrets:
+1 -1
View File
@@ -24,7 +24,7 @@ APP_DEBUG=
APP_URL=
LOG_CHANNEL=
BROADCAST_DRIVER=
CACHE_DRIVER=
CACHE_DRIVER=file
QUEUE_CONNECTION=
SESSION_DRIVER=
SESSION_LIFETIME=
+86
View File
@@ -0,0 +1,86 @@
name: CSSD-backend-publish
on:
push:
tags:
- '*' # run on any tag push
jobs:
build:
name: Run Publish Job
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
actions: read
packages: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2.10.0
- name: Log into registry git.meshkee.com
uses: docker/login-action@v2.2.0
with:
registry: git.meshkee.com
username: ${{ vars.DOCKER_USERNAME }}
password: ${{ vars.DOCKER_PASSWORD }}
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v4.2.1
with:
context: .
push: true
tags: |
git.meshkee.com/${{ gitea.repository }}:${{ gitea.ref_name }}
git.meshkee.com/${{ gitea.repository }}:latest
cache-from: type=registry,ref=git.meshkee.com/${{ gitea.repository }}:buildcache
cache-to: type=registry,ref=git.meshkee.com/${{ gitea.repository }}:buildcache,mode=max
# cache-from: type=local,src=/tmp/.buildx-cache
# cache-to: type=local,dest=/tmp/.buildx-cache
secrets: |
gitea_token=${{ secrets.TOKEN }}
# deploy:
# name: Deploy Job
# runs-on: ubuntu-latest
# permissions:
# contents: read
# security-events: write
# actions: read
# id-token: write
# steps:
# - name: Deploy to server
# uses: appleboy/ssh-action@v1.0.0
# with:
# host: ${{ secrets.SSH_HOST }}
# username: ${{ secrets.SSH_USER }}
# key: ${{ secrets.SSH_KEY }}
# port: 22
# script: |
# cd /apps/balout-backend
# docker pull git.meshkee.com/${{ gitea.repository }}:${{ gitea.ref_name }}
# IMAGE=git.meshkee.com/${{ gitea.repository }}:${{ gitea.ref_name }} docker compose run --rm balout-backend php artisan migrate --pretend --force
# # docker run --rm git.meshkee.com/${{ gitea.repository }}:${{ gitea.ref_name }} php artisan migrate --pretend --force
# if [ $? -eq 0 ]; then
# echo "Migration check passed. Deploying..."
# IMAGE=git.meshkee.com/${{ gitea.repository }}:${{ gitea.ref_name }} docker compose up -d
# # اجرای واقعی migration داخل کانتینر در حال اجرا
# docker exec balout-backend php artisan migrate --force
# else
# echo "Migration test failed, aborting deploy"
# exit 1
# fi
+4 -4
View File
@@ -84,7 +84,7 @@ deployment:
name: cssd-production-back-configmap
- secretRef:
name: cssd-production-back-secret
image: docker.willaspace.com/repository/docker-hosted/external-projects/cssd-back:latest
image: docker.meshkee.com/repository/docker-hosted/external-projects/cssd-back:latest
imagePullPolicy: IfNotPresent
# Additional labels for Deployment
@@ -193,7 +193,7 @@ deployment:
# Image of the app container
image:
repository: docker.willaspace.com/repository/docker-hosted/external-projects/cssd-back
repository: docker.meshkee.com/repository/docker-hosted/external-projects/cssd-back
tag: nginx-latest
digest: '' # if set to a non empty value, digest takes precedence on the tag
pullPolicy: IfNotPresent
@@ -258,7 +258,7 @@ deployment:
# Add additional containers besides init and app containers
additionalContainers:
- name: php-fpm
image: docker.willaspace.com/repository/docker-hosted/external-projects/cssd-back:latest
image: docker.meshkee.com/repository/docker-hosted/external-projects/cssd-back:latest
imagePullPolicy: IfNotPresent
envFrom:
- configMapRef:
@@ -315,7 +315,7 @@ deployment:
podLabels:
# env: prod
image: docker.willaspace.com/repository/docker-hosted/external-projects/cssd-back:latest
image: docker.meshkee.com/repository/docker-hosted/external-projects/cssd-back:latest
command:
- /usr/bin/supervisord
- -n
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,4 +1,4 @@
FROM docker.willaspace.com/repository/docker-hosted/standard-laravel:8.2-fpm
FROM docker.meshkee.com/repository/docker-hosted/standard-laravel:8.2-fpm
WORKDIR /var/www/html
@@ -11,7 +11,7 @@ COPY database /var/www/html/database
COPY composer.* /var/www/html/
RUN composer config --global http-basic.repo.willaspace.com $REGISTRY_USER_NAME $REGISTRY_PASSWORD
RUN composer config --global http-basic.repo.meshkee.com $REGISTRY_USER_NAME $REGISTRY_PASSWORD
RUN composer install --no-scripts
+42
View File
@@ -0,0 +1,42 @@
# Use the official PHP image as the base image
FROM 'docker-proxy.meshkee.com/php:8.2-fpm'
# Set working directory inside the container
WORKDIR /var/www/html
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip \
libzip-dev \
libpq-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libssl-dev \
libicu-dev \
g++ \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install pdo_mysql pdo_pgsql mbstring exif pcntl bcmath opcache intl zip
# Install Composer
COPY --from=docker-proxy.meshkee.com/composer:2 /usr/bin/composer /usr/bin/composer
# Copy application code into the container
COPY . .
# Install PHP dependencies
RUN composer install --no-interaction --prefer-dist --optimize-autoloader
# Set permissions for the Laravel project
RUN chown -R 1000:1000 /var/www/html \
&& chmod -R 777 /var/www/html/storage /var/www/html/bootstrap/cache
# Expose port 9000 for PHP-FPM
EXPOSE 9000
+12 -2
View File
@@ -1,3 +1,13 @@
FROM docker.willaspace.com/repository/docker-hosted/nginx:alpine
FROM docker.meshkee.com/repository/docker-hosted/node:14-alpine AS builder
COPY public /var/www/html/public
WORKDIR /var/www/html
COPY . /var/www/html/
RUN npm i
RUN npm run production
FROM docker.meshkee.com/repository/docker-hosted/nginx:alpine
COPY --from=builder /var/www/html/public /var/www/html/public
+1 -1
View File
@@ -6,5 +6,5 @@ class StatusTypeEnum
{
const APPROVED = "approved";
const REJECTED = "rejected";
const SUSPENDED = "suspended";
const PENDING = "pending";
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App\Events;
use App\Models\Cycle;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CycleSaved
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public Cycle $cycle;
public function __construct(Cycle $cycle)
{
$this->cycle = $cycle;
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
// new PrivateChannel('channel-name'),
];
}
}
@@ -0,0 +1,10 @@
<?php
namespace App\Exceptions;
use Exception;
class FieldNotExistsException extends Exception
{
}
+28
View File
@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Eloquent\Model;
if (!function_exists('pluckValues')) {
/**
* Extracts the values of a given key from an array of associative arrays.
*
* @param array $array The input array of associative arrays.
* @param string $key The key whose values need to be extracted.
* @return array An array containing the values of the specified key.
*/
function pluckValues(array $array, string $key): array
{
return array_map(function ($item) use ($key) {
return $item[$key] ?? null;
}, $array);
}
}
if (!function_exists('getNamespaceMap')) {
function getNamespaceMap(Model $model): string
{
return $model->getMorphClass();
}
}
@@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Packages\Messaging\src\Facades\MessageResponse;
use Spatie\Permission\Models\Role;
class RegisterController extends Controller
{
+5 -1
View File
@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Events\CycleSaved;
use App\Http\Requests\StoreCycleRequest;
use App\Http\Resources\CycleResource;
use App\Interfaces\CycleRepositoryInterface;
@@ -72,6 +73,8 @@ class CycleController extends Controller
foreach ( $Labels as $Label => $Count ) {
$CycleObj->labels()->attach( array( $Label ) , [ 'count' => $Count ] );
}
event(new CycleSaved($CycleObj));
return MessageResponse::success( trans( 'messages.success' ) );
}
@@ -109,6 +112,7 @@ class CycleController extends Controller
foreach ( $Labels as $Label => $Count ) {
$Cycle->labels()->attach( array( $Label ) , [ 'count' => $Count ] );
}
event(new CycleSaved($Cycle));
return MessageResponse::success( trans( 'messages.success' ) );
}
@@ -127,7 +131,7 @@ class CycleController extends Controller
public function verifyCycle( Cycle $Cycle )
{
if ( auth( 'api' )->user()->cant( 'verifyCycle' , $Cycle ) ) {
return MessageResponse::error( trans( 'You dont have permission' ) );
return MessageResponse::error( trans( 'messages.access_denied' ) );
}
if ( $Cycle->verified == 'Verified' ) {
$Cycle->verified = 'NotVerified';
+100 -2
View File
@@ -2,13 +2,37 @@
namespace App\Http\Controllers;
use App\Models\Cycle;
use App\Models\FakeModel;
use App\Models\Item;
use App\Models\Package;
use App\Services\ExportCollection;
use App\Services\Responser;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;
class ExportController extends Controller
{
private function sendToS3($export){
$fakeModel = FakeModel::firstOrCreate(['batch_id' => Str::random(6)]);
$tempFileName = 'excel_' . Str::random(10) . '.xlsx';
$tempDir = 'temp';
Storage::makeDirectory($tempDir);
$tempFilePath = $tempDir . '/' . $tempFileName;
Excel::store($export, $tempFilePath, 'local', \Maatwebsite\Excel\Excel::XLSX);
$media = $fakeModel->addMedia(storage_path('app/' . $tempFilePath))->toMediaCollection('temp_medias');
// اگه مشکلی پیش نمیاد بعد از این مرحله بالایی فیک مدل رو هم حذف کن که دیتابیس شلوغ نشه
Storage::delete($tempFilePath);
return $media;
}
public function items()
{
$Items = Item::with( [ 'user' => function ( $query ) {
@@ -66,8 +90,17 @@ class ExportController extends Controller
'نام بیمارستان',
'اخرین انتقال'
] );
$export = new ExportCollection( $Items );
return Excel::download( $export , 'items.xlsx' , null , [ \Maatwebsite\Excel\Excel::XLSX ] );
$media = $this->sendToS3($export);
return response()->json(
Responser::success(
'خروجی اکسل',
null,
['id' => $media->id, 'url' => $media->getUrl()]
)
);
}
public function packages()
@@ -121,6 +154,71 @@ class ExportController extends Controller
'اخرین انتقال'
] );
$export = new ExportCollection( $Packages );
return Excel::download( $export , 'packages.xlsx' , null , [ \Maatwebsite\Excel\Excel::XLSX ] );
$media = $this->sendToS3($export);
return response()->json(
Responser::success(
'خروجی اکسل',
null,
['id' => $media->id, 'url' => $media->getUrl()]
)
);
}
public function cycles()
{
$cycles = Cycle::with([
'user' => function ($query) {
$query->select('id', 'name', 'medical_center_id');
},
'user.medical_center' => function ($query) {
$query->select('id', 'name');
},
]);
$user = auth('api')->user();
if ($user->hasRole('User') or $user->hasRole('Supervisor')) {
$cycles = $cycles->whereHas('user', function ($query) use ($user) {
$query->where('medical_center_id', $user->medical_center_id);
});
}
$cycles = $cycles->orderByDesc('id')->get();
$cycles = $cycles->map(function ($item, $key) {
$row[] = $item["id"];
$row[] = $item["unique_id"];
$row[] = $item["note"];
$row[] = $item["sterilizer_id"];
$row[] = $item["cycle_number"];
$row[] = $item["user"] != null ? $item["user"]["id"] : null;
$row[] = $item["user"] != null ? $item["user"]["name"] : null;
$row[] = $item['user']['medical_center']['id'] ?? null;
$row[] = $item['user']['medical_center']['name'] ?? null;
return $row;
});
$cycles->prepend([
'شناسه آیتم',
'unique_id',
'یادداشت',
'sterilizer_id',
'cycle_number',
'شناسه کاربر',
'نام کاربر',
'شناسه بیمارستان',
'نام بیمارستان',
]);
$export = new ExportCollection($cycles);
$media = $this->sendToS3($export);
return response()->json(
Responser::success(
'خروجی اکسل',
null,
['id' => $media->id, 'url' => $media->getUrl()]
)
);
}
}
+51 -26
View File
@@ -16,9 +16,20 @@ class ItemController extends Controller
{
public function index( Request $request )
{
$Items = Item::when( $request->has( 'name' ) && $request->name != '' , function ( $query ) use ( $request ) {
$Items = Item::with( [
'user' ,
'package' ,
'user.medical_center' => function ( $query ) {
$query->select( 'id' , 'name' , 'address' , 'phone_number' );
} ,
] )->when( $request->has( 'name' ) && $request->name != '' , function ( $query ) use ( $request ) {
$query->where( 'name' , 'LIKE' , '%' . $request->name . '%' );
} )
} )
->when($request->filled('user_name'), function ($query) use ($request) {
$query->whereHas('user', function ($q) use ($request) {
$q->where('users.name', 'LIKE', '%' . $request->user_name . '%');
});
})
->when( $request->has( 'udi' ) && $request->udi != '' , function ( $query ) use ( $request ) {
$query->where( 'udi' , 'LIKE' , '%' . $request->udi . '%' );
} )
@@ -35,21 +46,10 @@ class ItemController extends Controller
$query->whereHas( 'user' , function ( $query ) use ( $request ) {
$query->where( 'medical_center_id' , $request->medical_center_id );
} );
} )
->with( [
'user' ,
'package' ,
'user.medical_center' => function ( $query ) {
$query->select( 'id' , 'name' , 'address' , 'phone_number' );
} ,
] );
} );
$user = auth( 'api' )->user();
if ( $user->hasRole( 'User' ) ) {
$Items = $Items->whereHas( 'user' , function ( $query ) use ( $user ) {
$query->where( 'medical_center_id' , $user->medical_center_id );
} )->where( "status" , StatusTypeEnum::APPROVED );
} elseif ( $user->hasRole( 'Supervisor' ) ) {
if ( $user->hasRole( 'User' ) or $user->hasRole( 'Supervisor' ) ) {
$Items = $Items->whereHas( 'user' , function ( $query ) use ( $user ) {
$query->where( 'medical_center_id' , $user->medical_center_id );
} );
@@ -96,12 +96,8 @@ class ItemController extends Controller
] );
$user = auth( 'api' )->user();
if ( $user->hasRole( 'User' ) ) {
if ( $user->hasRole( 'User' ) or $user->hasRole('Supervisor') ) {
$Items = $Items->where( "user_id" , $user->id );
} elseif ( $user->hasRole( 'Supervisor' ) ) {
$Items = $Items->whereHas( 'user' , function ( $query ) use ( $user ) {
$query->where( 'medical_center_id' , $user->medical_center_id );
} );
}
$Items = $Items->orderByDesc( 'id' )->paginate( 10 );
@@ -111,13 +107,13 @@ class ItemController extends Controller
public function getItems()
{
$user = auth()->user();
$medicalCenterId = optional(optional($user)->medical_center)->id;
$userIds = User::where('medical_center_id', $medicalCenterId)->pluck('id')->toArray();
$userId = auth('api')->id();
// $medicalCenterId = optional(optional($user)->medical_center)->id;
// $userIds = User::where('medical_center_id', $medicalCenterId)->pluck('id')->toArray();
$Items = Item::where( "status" , StatusTypeEnum::APPROVED )
->where( "package_id" , null )
->whereIn('creator_id', $userIds)
->where('user_id', $userId)
->orderByDesc( 'id' )
->isNotRepaired()
->get();
@@ -152,6 +148,35 @@ class ItemController extends Controller
return ItemResource::make( $Item );
}
public function showUdi( $udi )
{
$Item = Item::where('udi',$udi)->first();
$Item->load( [
'user' ,
'creator' ,
'package' ,
'user.medical_center' => function ( $query ) {
$query->select( 'id' , 'name' , 'address' , 'phone_number' );
} ,
"transfers" => function ( $query ) {
$query->with( [
'user' => function ( $query ) {
$query->select( 'id' , 'name' , 'cell_number' );
} ,
'user.medical_center' => function ( $query ) {
$query->select( 'id' , 'name' , 'address' , 'phone_number' );
},
'userTransfer' => function ($query) {
$query->select('id','name','cell_number');
}
] );
},
'media'
] );
return ItemResource::make( $Item );
}
public function store( StoreItemRequest $request )
{
$Item = Item::create( [
@@ -161,7 +186,7 @@ class ItemController extends Controller
'specific' => $request->specific ,
'note' => $request->note ,
'udi' => $request->udi ,
'status' => StatusTypeEnum::SUSPENDED ,
'status' => StatusTypeEnum::PENDING ,
'user_id' => auth( 'api' )->user()->id ,
'creator_id' => auth( 'api' )->user()->id
] );
@@ -171,7 +196,7 @@ class ItemController extends Controller
public function edit( Item $Item )
{
return ItemResource::make( $Item );
return ItemResource::make( $Item->load(['media']) );
}
public function update( StoreItemRequest $request , Item $Item )
+1 -1
View File
@@ -113,7 +113,7 @@ class LabelController extends Controller
$query->where('medical_center_id', $user->medical_center_id);
});
}
})->get();
})->where('enabled',true)->get();
return MessageResponse::data($Labels);
}
+23 -28
View File
@@ -13,50 +13,45 @@ class MessageController extends Controller
public function index(Request $request)
{
$User = auth('api')->user();
$role = null;
$medical_center_id = null;
$User = auth('api')->user();
if ($User->hasRole('Supervisor') || $User->hasRole('User')) {
$medical_center_id = $User->medical_center_id;
$role = 'Admin';
}
$remove = $User->id;
$Users = User::whereHas('messagesSent', function ($q) use ($User) {
$q->where('recipient_user_id', $User->id);
})
$Users = User::where(function ($query) use ($User) {
$query->whereHas('messagesSent', function ($q) use ($User) {
$q->where('recipient_user_id', $User->id);
})
->orWhereHas('messagesReceived', function ($q) use ($User) {
$q->where('sender_user_id', $User->id);
})
->when($medical_center_id, function ($query) use ($medical_center_id) {
$query->where('medical_center_id', $medical_center_id);
})
->when($role, function ($query) use ($role) {
$query->role($role);
})
->paginate(10);
});
})
->when($medical_center_id, function ($query) use ($medical_center_id) {
$query->where('medical_center_id', $medical_center_id);
})
->paginate(10);
foreach ($Users as $user) {
$UnReadReceivedMessages = Message::where('sender_user_id', $user->id)->where('recipient_user_id', $User->id)->where('status', 'UnRead')->get()->count();
$user->unread_messages_count = $UnReadReceivedMessages;
$user->unread_messages_count = Message::where('sender_user_id', $user->id)
->where('recipient_user_id', $User->id)
->where('status', 'UnRead')
->count();
$MessagesCount = Message::where(function ($query) use ($user, $User) {
$query->where('sender_user_id', $user->id)->where('recipient_user_id', $User->id);
$user->messages_count = Message::where(function ($query) use ($user, $User) {
$query->where('sender_user_id', $user->id)
->where('recipient_user_id', $User->id);
})->orWhere(function ($query) use ($user, $User) {
$query->where('sender_user_id', $User->id)->where('recipient_user_id', $user->id);
})->get()->count();
$user->messages_count = $MessagesCount;
$query->where('sender_user_id', $User->id)
->where('recipient_user_id', $user->id);
})->count();
}
//
// $Users = $Users->filter(function ($value, $key) use($remove){
// return $value['id'] != $remove;
// });
return MessageResponse::data($Users);
}
public function create()
{
+10 -12
View File
@@ -45,6 +45,7 @@ class PackageController extends Controller
})
->with([
'user',
'items',
'user.medical_center' => function ($query) {
$query->select('id', 'name', 'address', 'phone_number');
},
@@ -61,15 +62,11 @@ class PackageController extends Controller
]);
$user = auth('api')->user();
if ($user->hasRole('User')) {
if ($user->hasRole('User') or $user->hasRole('Supervisor')) {
$Packages = $Packages->where("user_id", $user->id);
} elseif ($user->hasRole('Supervisor')) {
$Packages = $Packages->whereHas('user', function ($query) use ($user) {
$query->where('medical_center_id', $user->medical_center_id);
});
}
$Packages = $Packages->orderByDesc('id')->get();
$Packages = $Packages->orderByDesc('id')->paginate(10);
return PackageResource::collection($Packages);
}
@@ -77,6 +74,7 @@ class PackageController extends Controller
public function getPackages()
{
$Packages = Package::where("status", StatusTypeEnum::APPROVED)
->where("user_id", auth('api')->id())
->orderByDesc('id')
->get();
return PackageResource::collection($Packages);
@@ -114,16 +112,16 @@ class PackageController extends Controller
$PackageData = [
'name' => $request->name,
'note' => $request->note,
'status' => StatusTypeEnum::SUSPENDED,
'status' => StatusTypeEnum::PENDING,
'user_id' => auth('api')->user()->id,
'creator_id' => auth('api')->user()->id
];
$Package = Package::create($PackageData);
foreach ($request->items as $itemId) {
$item = Item::where("id", $itemId)->first();
foreach ($request->items as $itemNameAndId) {
$item = Item::where("id", $itemNameAndId['id'])->first();
if ($item) {
$item->update([
"package_id" => $Package->id
'package_id' => $Package->id
]);
}
}
@@ -140,8 +138,8 @@ class PackageController extends Controller
{
$Package->update($request->except(['items']));
foreach ($request->items as $itemId) {
$item = Item::where("id", $itemId)->first();
foreach ($request->items as $itemNameAndId) {
$item = Item::where("id", $itemNameAndId['id'])->first();
if ($item) {
$item->update([
"package_id" => $Package->id
@@ -48,6 +48,11 @@ class TestResultController extends Controller
->when($request->has('testType_id') && $request->testType_id, function ($query) use ($request) {
$query->where('test_type_id', $request->testType_id);
})
->when($request->has('test_type_name') && $request->test_type_name, function ($q) use ($request) {
$q->whereHas('test_type', function ($query) use ($request) {
$query->where('name', 'like', "%{$request->test_type_name}%");
});
})
->when(($request->has('device_id') && $request->device_id) && ($request->has('device_label') && $request->device_label && $request->device_label != "undefined"), function ($query) use ($request) {
if ($request->device_label != 'undefined') {
$query->whereHas('input_values', function ($query) use ($request) {
@@ -218,6 +223,7 @@ class TestResultController extends Controller
public function edit(TestResult $TestResult)
{
$TestResult->load('media');
foreach ($TestResult->input_values as $key => $value) {
$input = $value->input;
if ($input->type == 'Checkbox' || $input->type == 'Select' || $input['type'] == 'Radiobutton') {
@@ -320,7 +326,7 @@ class TestResultController extends Controller
public function verifyTestResult(TestResult $TestResult, $Value)
{
if (auth('api')->user()->cant('verifyTestResult', $TestResult)) {
return MessageResponse::error(trans('You dont have permission or this test result belongs to another medical center'));
return MessageResponse::error('messages.access_denied');
}
$TestResult->verified = $Value;
@@ -391,7 +397,7 @@ class TestResultController extends Controller
public function showTestResult($id)
{
$TestResult = TestResult::with('input_values', 'user.medical_center', 'test_type')->select('result', 'verified', 'device_id', 'user_id', 'id', 'test_type_id', 'created_at')->findOrFail($id);
$TestResult = TestResult::with('input_values', 'user.medical_center', 'test_type','media')->select('result', 'verified', 'device_id', 'user_id', 'id', 'test_type_id', 'created_at')->findOrFail($id);
$options = [];
foreach ($TestResult->input_values as $value) {
$input = $value->input;
+14 -13
View File
@@ -7,6 +7,7 @@ use App\Models\Input;
use App\Models\Option;
use App\Models\TestResult;
use App\Models\TestType;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Milon\Barcode\Facades\DNS1DFacade;
@@ -380,21 +381,20 @@ class TestTypeController extends Controller
/////////////////////////////////////////////////////////////////////////////////////
public function getInputs(Request $request)
public function getInputs($idOrCode)
{
if (auth('api')->user()->can('getInputs')) {
return MessageResponse::error(trans('messages.failed'));
}
if ($request->test_result_id !== '') {
$testTypeId = TestResult::find($request->test_result_id);
}
if (isset($testTypeId) && $testTypeId) {
$testType = TestType::select('id', 'name', 'unique_code', 'device_label')->find($testTypeId->test_type_id);
} else {
$testType = TestType::where('name', $request->name)->orWhere('unique_code', $request->unique_code)->select('id', 'name', 'unique_code', 'device_label')->first();
}
if (isset($testType) && $testType) {
try {
$by = request()->query('by', 'id');
$testType = TestType::select('id', 'name', 'unique_code', 'device_label');
if ($by === 'code') {
$testType = $testType->where('unique_code', $idOrCode)->firstOrFail();
} else {
$testType = $testType->findOrFail($idOrCode);
}
$inputs = Input::select('id', 'name', 'type', 'size', 'parent_id', 'require_scanner')->with(
['options' => function ($query) {
$query->select('id', 'title', 'input_id');
@@ -408,13 +408,14 @@ class TestTypeController extends Controller
)->whereNull('parent_id')->where('test_type_id', $testType->id)->get();
return MessageResponse::data(['testType' => $testType, 'inputs' => $inputs]);
} catch(Exception $e) {
return MessageResponse::error();
}
return MessageResponse::error();
}
public function listNames()
public function list()
{
$testType = TestType::pluck('name');
$testType = TestType::select('id','name')->get();
return MessageResponse::data($testType);
}
@@ -8,16 +8,25 @@ use App\Http\Requests\StoreTransferRequest;
use App\Http\Resources\TransferResource;
use App\Models\Item;
use App\Models\Transfer;
use App\Policies\TransferPolicy;
use Carbon\Carbon;
use Packages\Messaging\src\Facades\MessageResponse;
class TransferItemController extends Controller
{
private $policy;
public function __construct(TransferPolicy $policy)
{
$this->policy = $policy;
}
public function getSuspendedTransfer()
{
$data = Transfer::query()
->whereHasMorph( 'transferable' , [ Item::class ] )
->where( "status" , StatusTypeEnum::SUSPENDED )
->where( "status" , StatusTypeEnum::PENDING )
->with( [ "user" , "transferable" , "transferable.user" ] );
$user = auth( 'api' )->user();
@@ -41,7 +50,7 @@ class TransferItemController extends Controller
if ( auth( 'api' )->user()->cant( 'changeStatus' , [ Transfer::class , $Transfer ] ) ) {
return MessageResponse::error( trans( 'messages.access_denied' ) );
}
if ( $Transfer->status == StatusTypeEnum::SUSPENDED ) {
if ( $Transfer->status == StatusTypeEnum::PENDING ) {
if ( $request->status == StatusTypeEnum::APPROVED ) {
$item = $Transfer->transferable;
if ( $item->transferActive ) $item->transferActive()->update( [ "to_date" => Carbon::now() ] );
@@ -58,9 +67,10 @@ class TransferItemController extends Controller
public function transfer( StoreTransferRequest $request , Item $Item )
{
if ( auth( 'api' )->user()->cant( 'transferItem' , [ Transfer::class , $Item ] ) ) {
if (!$this->policy->transferItem(auth('api')->user(), $Item)) {
return MessageResponse::error( trans( 'messages.access_denied' ) );
}
if ( $Item->user_id != $request->user_id ) {
$Item->transfers()->create( [
"user_transfer_id" => auth()->user()->id,
@@ -17,7 +17,7 @@ class TransferPackageController extends Controller
{
$data = Transfer::query()
->whereHasMorph( 'transferable' , [ Package::class ] )
->where( "status" , StatusTypeEnum::SUSPENDED )
->where( "status" , StatusTypeEnum::PENDING )
->with( [ "user" , "transferable" , "transferable.user" ] );
$user = auth( 'api' )->user();
@@ -41,7 +41,7 @@ class TransferPackageController extends Controller
if ( auth( 'api' )->user()->cant( 'changeStatus' , [ Transfer::class , $Transfer ] ) ) {
return MessageResponse::error( trans( 'messages.access_denied' ) );
}
if ( $Transfer->status == StatusTypeEnum::SUSPENDED ) {
if ( $Transfer->status == StatusTypeEnum::PENDING ) {
if ( $request->status == StatusTypeEnum::APPROVED ) {
$package = $Transfer->transferable;
if ( $package->transferActive ) $package->transferActive()->update( [ "to_date" => Carbon::now() ] );
+29 -27
View File
@@ -179,14 +179,14 @@ class UserController extends Controller
if ( auth( 'api' )->user()->cant( 'getByMedicalCenter' , $MedicalCenter ) ) {
return MessageResponse::error( trans( 'messages.failed' ) );
}
if ($user->hasRole('Admin')){
$MedicalCenter = MedicalCenter::with(['users' => function ($query) {
$query->select('id', 'medical_center_id', 'name', 'cell_number', 'status')
->whereDoesntHave('roles', function ($roleQuery) {
$roleQuery->where('name', 'Admin');
});
}, 'users.roles'])->get();
}else{
// if ($user->hasRole('Admin')){
// $MedicalCenter = MedicalCenter::with(['users' => function ($query) {
// $query->select('id', 'medical_center_id', 'name', 'cell_number', 'status')
// ->whereDoesntHave('roles', function ($roleQuery) {
// $roleQuery->where('name', 'Admin');
// });
// }, 'users.roles'])->get();
// }else{
$MedicalCenter = $MedicalCenter->load( [ 'users' => function ( $query ) use ( $user ) {
if ( $user->hasRole( 'User' ) ) {
return $query->select( [ 'id' , 'medical_center_id' , 'name' , 'cell_number' , 'status' ] )->where( 'id' , $user->id );
@@ -197,7 +197,7 @@ class UserController extends Controller
});
}
} , 'users.roles' ] );
}
// }
return MessageResponse::data( $MedicalCenter );
}
@@ -227,6 +227,7 @@ class UserController extends Controller
return MessageResponse::error( trans( 'messages.access_denied' ) );
}
$User->syncRoles( $request->roles );
$User->load('roles');
return MessageResponse::data( $User );
}
@@ -251,27 +252,28 @@ class UserController extends Controller
return MessageResponse::data( [ 'ReceivedMessages' => $ReceivedMessages , 'SentMessages' => $SentMessages ] );
}
public function searchUser( Request $request )
public function searchUser(Request $request)
{
$role = null;
$medical_center_id = null;
$User = auth('api')->user();
$User = auth( 'api' )->user();
if ( $User->hasRole( 'Supervisor' ) || $User->hasRole( 'User' ) ) {
$medical_center_id = $User->medical_center_id;
if ( $User->hasRole( 'Supervisor' ) ) {
$role = 'Admin';
}
$query = User::query()
->with('roles')
->where('id', '<>', $User->id)
->select('id', 'name')
->where('name', 'LIKE', '%' . $request->name . '%');
if ($User->hasRole('Supervisor') || $User->hasRole('User')) {
$query->where(function ($q) use ($User) {
$q->where('medical_center_id', $User->medical_center_id)
->orWhereHas('roles', function ($roleQuery) {
$roleQuery->where('name', 'Admin');
});
});
}
$users = User::where( 'id' , '<>' , $User->id )->select( 'id' , 'name' )->where( 'name' , 'LIKE' , '%' . $request->name . '%' )
->when( $medical_center_id , function ( $query ) use ( $medical_center_id ) {
$query->where( 'medical_center_id' , $medical_center_id );
} )
->when( $role , function ( $query ) use ( $role ) {
$query->role( $role );
} )
->get();
return MessageResponse::data( $users );
$users = $query->get();
return MessageResponse::data($users);
}
}
+5 -2
View File
@@ -3,6 +3,7 @@
namespace App\Http\Requests;
use App\Models\Cycle;
use App\Rules\ValidEnabledLabels;
use Illuminate\Foundation\Http\FormRequest;
@@ -25,9 +26,10 @@ class StoreCycleRequest extends FormRequest
return [
'date' => 'required',
'sterilizer_id' => 'required',
'cycle_number' => 'required',
'cycle_number' => 'required|unique:cycles,cycle_number',
'note' => 'nullable',
'labels.*.id' => 'required|numeric|exists:labels,id',
'labels' => ['required','array','distinct',new ValidEnabledLabels()],
];
break;
}
@@ -37,9 +39,10 @@ class StoreCycleRequest extends FormRequest
return [
'date' => 'required',
'sterilizer_id' => 'required',
'cycle_number' => 'required',
'cycle_number' => 'required|unique:cycles,cycle_number',
'note' => 'nullable',
'labels.*.id' => 'required|numeric|exists:labels,id',
'labels' => ['required','array','distinct',new ValidEnabledLabels()],
];
break;
+5 -2
View File
@@ -2,6 +2,7 @@
namespace App\Http\Requests;
use App\Rules\ValidateItemOwnership;
use Illuminate\Foundation\Http\FormRequest;
class StorePackageRequest extends FormRequest
@@ -23,7 +24,8 @@ class StorePackageRequest extends FormRequest
return [
'name' => 'required|max:250',
'note' => 'nullable',
'items' => 'required',
'items' => 'required|array|min:1',
'items.*.id' => ['exists:items,id','integer',new ValidateItemOwnership()],
];
break;
}
@@ -33,7 +35,8 @@ class StorePackageRequest extends FormRequest
return [
'name' => 'required|max:250',
'note' => 'nullable',
'items' => 'required',
'items' => 'required|array|min:1',
'items.*.id' => ['exists:items,id','integer',new ValidateItemOwnership()],
];
break;
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace App\Listeners;
use App\Events\CycleSaved;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class UpdateLabelsCycleNumber
{
/**
* Create the event listener.
*/
public function __construct()
{
//
}
/**
* Handle the event.
*/
public function handle(CycleSaved $event): void
{
$cycle = $event->cycle;
$cycleNumber = $cycle->cycle_number;
$cycle->labels()->update(['cycle_number' => $cycleNumber, 'enabled' => false]);
}
}
+84
View File
@@ -0,0 +1,84 @@
<?php
namespace App\Models;
use App\Exceptions\FieldNotExistsException;
// use App\Scopes\OrderByIdScope;
use Illuminate\Support\Arr;
trait BasicModel
{
private int $pageSizeLimit = 48;
protected static function boot()
{
parent::boot();
// if (! app()->runningInConsole()) {
// static::addGlobalScope( new OrderByIdScope );
// }
}
public function getPerPage()
{
$pageSize = (int) request( 'per_page' , $this->perPage );
return min( $pageSize , $this->pageSizeLimit );
}
public function attributeExists( $attr ): bool
{
return array_key_exists( $attr , $this->attributes );
}
public function getField( $name )
{
$columnName = static::getColumn( $name );
return $this->$columnName;
}
public function setField( $name , $value ): void
{
$columnName = static::getColumn( $name );
$this->$columnName = $value;
}
public static function getColumnTable( $name ): string
{
return static::getTableName() . '.' . static::getColumn( $name );
}
public static function getColumn( $name )
{
$fieldName = Arr::get( static::$maps , $name );
if ( is_null( $fieldName ) ) {
throw new FieldNotExistsException( "field $name not exists" );
}
return $fieldName;
}
public function getTable()
{
return static::getTableName();
}
public function fieldValue( $name )
{
return $this->$name;
}
public function getAttributes()
{
return $this->attributes;
}
public function isLoaded( $relationName ): bool
{
return isset( $this->relations[ $relationName ] ) and $this->$relationName != null;
}
abstract public static function getTableName();
}
+2
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Events\CycleSaved;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -14,6 +15,7 @@ class Cycle extends Model
'date', 'user_id', 'cycle_number', 'sterilizer_id', 'note', 'verified', 'unique_id'
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Sms extends Model
{
use BasicModel;
protected $fillable = [
'client_id' , 'status_code' , 'status' , 'message' , 'rel_id' , 'rel_type' , 'cell_number' , 'segment_count' ,
];
protected $hidden = [];
public static function getTableName(): string
{
return "sms";
}
public function receiver(): MorphTo
{
return $this->morphTo( null , 'rel_type' , 'rel_id' );
}
public function smsBatch(): BelongsTo
{
return $this->belongsTo( SmsBatch::class );
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class SmsBatch extends Model
{
use SoftDeletes , BasicModel;
protected $fillable = [
'category' , 'operator' , 'code' , 'fee' , 'type' , 'business_id' , 'is_admin' , 'is_systematic' , 'pattern' , 'from'
];
protected $hidden = [];
public static function getTableName(): string
{
return "sms_batch";
}
public function smsList(): HasMany
{
return $this->hasMany( Sms::class );
}
public function scopeSingle( $query )
{
return $query->whereCategory( 'single' );
}
public function scopeBatch( $query )
{
return $query->whereCategory( 'batch' );
}
}
+11
View File
@@ -27,11 +27,22 @@ class User extends Authenticatable
'email_verified_at' => 'datetime',
];
public array $messageFields = [
'name', 'cell_number'
];
protected function getDefaultGuardName(): string { return 'api'; }
public function medical_center(): BelongsTo
{
return $this->belongsTo(MedicalCenter::class);
}
public function getPhone()
{
return $this->cell_number;
}
public function test_results(): HasMany
{
return $this->hasMany(TestResult::class);
+6 -4
View File
@@ -2,6 +2,7 @@
namespace App\Policies;
use App\Constants\StatusTypeEnum;
use App\Models\Item;
use App\Models\User;
@@ -17,11 +18,12 @@ class ItemPolicy
{
if ($user->hasRole('Admin')) {
return true;
} elseif ($user->hasRole('Supervisor')) {
if ($Item->status == 0) {
return true;
}
} elseif ($user->hasRole('Supervisor') && $Item->user->medical_center_id == $user->medical_center_id) {
return true;
} elseif ($user->hasRole('User') && $Item->user_id == $user->id && $Item->status != StatusTypeEnum::APPROVED) {
return true;
}
return false;
}
public function update(User $user, Item $Item)
+13 -9
View File
@@ -17,18 +17,22 @@ class TransferPolicy
public function transferItem(User $user, Item $Item)
{
if ($user->hasRole('Admin')) {
return true;
} else {
if ($user->hasRole('Supervisor')) {
if ($Item->user->medical_center_id == $user->medical_center_id) {
return true;
}
if(is_null($Item->package_id)){
if ($user->hasRole('Admin')) {
return true;
} else {
if ($Item->user_id == $user->id) {
return true;
if ($user->hasRole('Supervisor')) {
if ($Item->user->medical_center_id == $user->medical_center_id) {
return true;
}
} else {
if ($Item->user_id == $user->id) {
return true;
}
}
}
} else {
return false;
}
}
+3
View File
@@ -18,6 +18,9 @@ class EventServiceProvider extends ServiceProvider
Registered::class => [
SendEmailVerificationNotification::class,
],
\App\Events\CycleSaved::class => [
\App\Listeners\UpdateLabelsCycleNumber::class,
],
];
/**
-1
View File
@@ -41,7 +41,6 @@ class CycleRepository implements CycleRepositoryInterface
->whereHas('user', function ($query) use ($user) {
$query->where('medical_center_id', $user->medical_center_id);
})
->where("user_id", $user->id)
->orderByDesc('id')
->paginate(10);
}
+16 -1
View File
@@ -12,6 +12,9 @@ class LabelRepository implements LabelRepositoryInterface
return Label::when($request->has('sterilizer_id') && $request->sterilizer_id != '', function ($query) use ($request) {
$query->where('sterilizer_id', $request->sterilizer_id);
})
->when($request->has('package_name') && $request->package_name != '', function ($query) use ($request) {
$this->applyPackageNameFilter($query,$request);
})
->when($request->has('cycle_number') && $request->cycle_number != '', function ($query) use ($request) {
$query->where('cycle_number', $request->cycle_number);
})
@@ -40,7 +43,6 @@ class LabelRepository implements LabelRepositoryInterface
->whereHas('user', function ($query) use ($user) {
$query->where('medical_center_id', $user->medical_center_id);
})
->where("user_id", $user->id)
->orderByDesc('id')
->paginate(10);
}
@@ -50,6 +52,9 @@ class LabelRepository implements LabelRepositoryInterface
return Label::when($request->has('sterilizer_id') && $request->sterilizer_id != '', function ($query) use ($request) {
$query->where('sterilizer_id', $request->sterilizer_id);
})
->when($request->has('package_name') && $request->package_name != '', function ($query) use ($request) {
$this->applyPackageNameFilter($query,$request);
})
->when($request->has('cycle_number') && $request->cycle_number != '', function ($query) use ($request) {
$query->where('cycle_number', $request->cycle_number);
})
@@ -87,6 +92,9 @@ class LabelRepository implements LabelRepositoryInterface
return Label::when($request->has('sterilizer_id') && $request->sterilizer_id != '', function ($query) use ($request) {
$query->where('sterilizer_id', $request->sterilizer_id);
})
->when($request->has('package_name') && $request->package_name != '', function ($query) use ($request) {
$this->applyPackageNameFilter($query,$request);
})
->when($request->has('cycle_number') && $request->cycle_number != '', function ($query) use ($request) {
$query->where('cycle_number', $request->cycle_number);
})
@@ -115,4 +123,11 @@ class LabelRepository implements LabelRepositoryInterface
->orderByDesc('id')
->paginate(10);
}
public function applyPackageNameFilter($q,$request)
{
return $q->whereHas('package', function ($query) use ($request) {
$query->where('packages.name', 'like', "%{$request->package_name}%");
});
}
}
+51 -31
View File
@@ -10,9 +10,19 @@ class PackageRepository implements PackageRepositoryInterface
{
public function indexForUser($request, $user)
{
return Package::when($request->has('name') && $request->name != '', function ($query) use ($request) {
$query->where('name', 'LIKE', '%'.$request->name.'%');
})
return Package::with([
'user',
'user.medical_center' => function ($query) {
$query->select('id', 'name', 'address', 'phone_number');
},
'items'
])
->tap(function ($query) use ($request) {
$this->applyUserNameFilter($query, $request);
})
->when($request->has('name') && $request->name != '', function ($query) use ($request) {
$query->where('name', 'LIKE', '%'.$request->name.'%');
})
->when($request->has('package_id') && $request->package_id != '', function ($query) use ($request) {
$query->where('id', $request->package_id);
})
@@ -21,26 +31,29 @@ class PackageRepository implements PackageRepositoryInterface
$query->where('medical_center_id', $request->medical_center_id);
});
})
->with([
'user',
'user.medical_center' => function ($query) {
$query->select('id', 'name', 'address', 'phone_number');
},
])
->whereHas('user', function ($query) use ($user) {
$query->where('medical_center_id', $user->medical_center_id);
$query->where('users.medical_center_id', $user->medical_center_id);
})
->where("user_id", $user->id)
->orWhere("status", StatusTypeEnum::APPROVED)
// ->where("status", StatusTypeEnum::APPROVED)
->orderByDesc('id')
->paginate(10);
}
public function indexForSupervisor($request, $user)
{
return Package::when($request->has('name') && $request->name != '', function ($query) use ($request) {
$query->where('name', 'LIKE', '%'.$request->name.'%');
})
return Package::with([
'user',
'user.medical_center' => function ($query) {
$query->select('id', 'name', 'address', 'phone_number');
},
'items'
])
->tap(function ($query) use ($request) {
$this->applyUserNameFilter($query, $request);
})
->when($request->has('name') && $request->name != '', function ($query) use ($request) {
$query->where('name', 'LIKE', '%'.$request->name.'%');
})
->when($request->has('package_id') && $request->package_id != '', function ($query) use ($request) {
$query->where('id', $request->package_id);
})
@@ -49,13 +62,8 @@ class PackageRepository implements PackageRepositoryInterface
$query->where('medical_center_id', $request->medical_center_id);
});
})
->with([
'user',
'user.medical_center' => function ($query) {
$query->select('id', 'name', 'address', 'phone_number');
},
])->whereHas('user', function ($query) use ($user) {
$query->where('medical_center_id', $user->medical_center_id);
->whereHas('user', function ($query) use ($user) {
$query->where('users.medical_center_id', $user->medical_center_id);
})
->orderByDesc('id')
->paginate(10);
@@ -63,9 +71,19 @@ class PackageRepository implements PackageRepositoryInterface
public function indexForAdmin($request, $user)
{
return Package::when($request->has('name') && $request->name != '', function ($query) use ($request) {
$query->where('name', 'LIKE', '%'.$request->name.'%');
})
return Package::with([
'user',
'user.medical_center' => function ($query) {
$query->select('id', 'name', 'address', 'phone_number');
},
'items'
])
->tap(function ($query) use ($request) {
$this->applyUserNameFilter($query, $request);
})
->when($request->has('name') && $request->name != '', function ($query) use ($request) {
$query->where('name', 'LIKE', '%'.$request->name.'%');
})
->when($request->has('package_id') && $request->package_id != '', function ($query) use ($request) {
$query->where('id', $request->package_id);
})
@@ -74,13 +92,15 @@ class PackageRepository implements PackageRepositoryInterface
$query->where('medical_center_id', $request->medical_center_id);
});
})
->with([
'user',
'user.medical_center' => function ($query) {
$query->select('id', 'name', 'address', 'phone_number');
},
])
->orderByDesc('id')
->paginate(10);
}
private function applyUserNameFilter($queryBuilder,$request){
return $queryBuilder->when($request->filled('user_name'), function ($query) use ($request) {
$query->whereHas('user', function ($q) use ($request) {
$q->where('users.name', 'LIKE', '%' . $request->user_name . '%');
});
});
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace App\Rules;
use App\Models\Label;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class ValidEnabledLabels implements ValidationRule
{
/**
* Run the validation rule.
*
* @param \Closure(string, ?string=): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$formattedVal = pluckValues($value,'id');
$validIds = Label::whereIn('id', $formattedVal)
->where('enabled', true)
->pluck('id')
->toArray();
if(count(array_diff($formattedVal, $validIds)) !== 0)
{
$fail('the :attribute must be enabled.');
}
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App\Rules;
use App\Models\Item;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class ValidateItemOwnership implements ValidationRule
{
/**
* Run the validation rule.
*
* @param \Closure(string, ?string=): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$item = Item::find($value);
if(!($item && $item->user_id === auth()->id())){
$fail(":attribute have invalid ownership");
}
}
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class OrderByIdScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->orderBy($model->getTable().'.id', 'desc');
}
}
@@ -0,0 +1,52 @@
<?php
namespace App\Services\Notification\Batch;
use Illuminate\Support\Collection;
class BatchTransmitter
{
protected Collection $collection;
protected mixed $config;
protected $message;
public function __construct( Collection $collection )
{
$this->collection = $collection;
$this->config = config( 'notification.drivers.rahyab_advertise' );
$this->client = new \SoapClient( $this->config[ 'url' ] );
}
public function send( string $message )
{
$this->message = $message;
if ( $this->collection->count() <= config( 'notification.max_phone_size.do_send_sms' ) ) {
return $result = $this->client->doSendSMS( $this->payload() );
}
}
protected function getPhones()
{
$phones = [];
foreach ( $this->collection as $key => $item ) {
$phones[] = $item->getPhone();
}
return array_unique( $phones );
}
protected function payload()
{
return array(
'uUsername' => $this->config[ 'username' ] ,
'uPassword' => $this->config[ 'password' ] ,
'uNumber' => $this->config[ 'from' ] ,
'uCellphones' => implode( ';' , $this->getPhones() ) ,
'uMessage' => $this->message ,
'uFarsi' => true ,
'uTopic' => false ,
'uFlash' => false ,
'uUDH' => ''
);
}
}
@@ -0,0 +1,163 @@
<?php
namespace App\Services\Notification\Batch;
use App\Models\SmsBatch;
use App\Services\Notification\Events\SmsSent;
use App\Services\Notification\Events\SmsSentAgain;
use App\Services\Notification\MessagePattern\Pattern;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use SoapClient;
class PeerToPeer
{
protected Collection $collection;
protected array $config;
protected Pattern $messagePatternClass;
protected string $messagePattern;
protected string $operator;
protected bool $isAdmin = false;
protected bool $isSystematic = false;
protected int $price = -80;
public function __construct(string $message, Collection $collection, string $category, $uniqueCode, $operator = 'advertise')
{
if ($this->isValidCost() || $operator == 'service') {
$this->operator = ($operator == 'advertise') ? 'rahyab_advertise' : 'rahyab_service';
$this->collection = $collection;
$this->messagePatternClass = new Pattern($message);
$this->messagePattern = $this->messagePatternClass->getPattern();
$this->config = array_merge($this->createExtra($category, $uniqueCode), config('notification.drivers.' . $this->operator));
if (isset($this->config['operator'])) {
if (str_contains($this->config['operator'], 'advertise')) {
$this->config['type'] = 'advertise';
} else {
$this->config['type'] = 'service';
}
}
try {
$this->client = new SoapClient( $this->config[ 'url' ] );
} catch ( \SoapFault $e ) {
dd($e->getMessage());
}
}
}
private function isValidCost(): bool
{
if ( $this->price > -50000.00) {
return true;
} else {
return false;
}
}
public function isSystematic($isSystematic = 0): static
{
$this->isSystematic = $isSystematic;
return $this;
}
public function isAdmin($isAdmin = 0): static
{
$this->isAdmin = $isAdmin;
return $this;
}
public function send($userData): void
{
if ($this->collection->count() <= config('notification.max_phone_size.do_send_sms_array_c')) {
$this->setIsAdminAndIsSystematicInConfig();
$payload = $this->payload($userData);
$response = $this->client->doSendSMSArrayC($payload)->doSendSMSArrayCResult->DataSendOut;
$this->serializeToDatabase($payload['uDataSendIn'], $response);
}
}
public function sendAgain($userData, SmsBatch $smsBatch): void
{
if ($this->collection->count() <= config('notification.max_phone_size.do_send_sms_array_c')) {
$payload = $this->payload($userData);
$response = $this->client->doSendSMSArrayC($payload)->doSendSMSArrayCResult->DataSendOut;
$this->updateToDatabase($payload['uDataSendIn'], $response, $smsBatch);
}
}
protected function payload($userData): array
{
$data = [];
foreach ($this->collection as $key => $item) {
$data[$key] = $this->prepareData($item, $userData);
}
return array(
'uUsername' => $this->config['username'],
'uPassword' => $this->config['password'],
'uDataSendIn' => $data
);
}
protected function prepareData(Model $model, $userData): array
{
$fillable = is_null($userData) ? $model : $userData;
return [
'ClientID' => rand(1, 1000000000000000),
'ShortCode' => $this->findFrom(),
'Cellphone' => $model->getPhone(),
'Message' => $this->messagePatternClass->fill($fillable),
'Farsi' => true,
'Flash' => false,
'UDH' => '',
'ServiceID' => ''
];
}
protected function findFrom()
{
$smsOperatorConfig = collect(config('notification.config_system'));
if (is_null($smsOperatorConfig) or $smsOperatorConfig->isEmpty()) {
return $this->config['from'];
}
$customConfig = $smsOperatorConfig->getConfig($this->operator);
if (is_null($customConfig)) {
return $this->config['from'];
}
return $customConfig['from'];
}
protected function serializeToDatabase($payload, $response): void
{
$this->collection->count() > 1 ?: $response = [$response];
event(new SmsSent($this->collection, json_decode(json_encode($response), true), $payload, $this->config));
}
protected function updateToDatabase($payload, $response, $smsBatch): void
{
$this->collection->count() > 1 ?: $response = [$response];
event(new SmsSentAgain($this->collection, json_decode(json_encode($response), true), $payload, $this->config, $smsBatch));
}
protected function createExtra($category, $uniqueCode): array
{
$extra ['is_admin'] = $this->isAdmin;
$extra ['is_systematic'] = $this->isSystematic;
$extra ['category'] = $category;
$extra ['operator'] = 'rahyab_advertise';
$extra ['code'] = $uniqueCode;
$extra ['messagePattern'] = $this->messagePattern;
$extra['className'] = $this->collection->isEmpty() ? null : getNamespaceMap($this->collection->first());
return $extra;
}
private function setIsAdminAndIsSystematicInConfig(): void
{
$this->config['is_admin'] = $this->isAdmin;
$this->config['is_systematic'] = $this->isSystematic;
}
}
+143
View File
@@ -0,0 +1,143 @@
<?php
namespace App\Services\Notification\Batch;
use App\Models\SmsBatch;
use App\Services\Notification\Events\SmsSent;
use App\Services\Notification\Events\SmsSentAgain;
use App\Services\Notification\MessagePattern\Pattern;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\Model;
class SimCard
{
protected Collection $collection;
protected array $config;
protected Pattern $messagePatternClass;
protected string $messagePattern;
protected array $payload;
protected bool $isAdmin = false;
protected bool $isSystematic = false;
public function __construct( $message , Collection $collection , string $category , $uniqueCode )
{
$this->collection = $collection;
$this->messagePatternClass = new Pattern( $message );
$this->messagePattern = $this->messagePatternClass->getPattern();
$this->config = array_merge( $this->createExtra( $category , $uniqueCode ) , config( 'notification.drivers.simcard' ) );
if ( isset( $this->config[ 'operator' ] ) ) {
$this->config[ 'type' ] = 'simcard';
}
$this->client = new \SoapClient( $this->config[ 'url' ] , array( 'trace' => 1 ) );
}
public function isSystematic( $isSystematic = 0 ): static
{
$this->isSystematic = $isSystematic;
return $this;
}
public function isAdmin( $isAdmin = 0 ): static
{
$this->isAdmin = $isAdmin;
return $this;
}
public function send( $userData ): void
{
if ( $this->collection->count() <= config( 'notification.max_phone_size.do_send_sms_array_c' ) ) {
$this->setIsAdminAndIsSystematicInConfig();
$payload = $this->payload( $userData );
$response = $this->client->SendSMS( $payload[ 'from' ] , $payload[ 'numbers' ] , $payload[ 'messages' ] , $payload[ 'username' ] , $payload[ 'password' ] , $payload[ 'time' ] , $payload[ 'op' ] );
$response = json_decode( $response );
$this->serializeToDatabase( json_decode( $response[ count( $response ) - 1 ] )[ 1 ] );
}
}
public function sendAgain( $userData , SmsBatch $smsBatch ): void
{
if ( $this->collection->count() <= config( 'notification.max_phone_size.do_send_sms_array_c' ) ) {
$payload = $this->payload( $userData );
$response = $this->client->SendSMS( $payload[ 'from' ] , $payload[ 'numbers' ] , $payload[ 'messages' ] , $payload[ 'username' ] , $payload[ 'password' ] , $payload[ 'time' ] , $payload[ 'op' ] );
$response = json_decode( $response );
$this->updateToDatabase( $response , $smsBatch );
}
}
protected function payload( $userData ): array
{
$data = [
'username' => $this->config[ 'username' ] ,
'password' => $this->config[ 'password' ] ,
'from' => $this->config[ 'from' ] ,
'op' => "pointtopoint" ,
'time' => '' ,
];
foreach ( $this->collection as $key => $item ) {
$modelData = $this->prepareData( $item , $userData );
$this->payload[] = $modelData;
$data[ 'numbers' ][] = $modelData[ 'Cellphone' ];
$data[ 'messages' ][] = $modelData[ 'Message' ];
}
return $data;
}
protected function prepareData( Model $model , $userData ): array
{
$fillable = is_null( $userData ) ? $model : $userData;
return [
'Cellphone' => $model->getPhone() ,
'Message' => $this->messagePatternClass->fill( $fillable ) ,
];
}
protected function serializeToDatabase( $response ): void
{
$response = $this->prepareResponse( $response );
event( new SmsSent( $this->collection , json_decode( json_encode( $response ) , true ) , $this->payload , $this->config ) );
}
protected function updateToDatabase( $response , $smsBatch ): void
{
$response = $this->prepareResponse( $response );
event( new SmsSentAgain( $this->collection , json_decode( json_encode( $response ) , true ) , $this->payload , $this->config , $smsBatch ) );
}
protected function prepareResponse( $response ): array
{
$result = [];
foreach ( $response as $value ) {
$result[] = [
'ClientID' => null ,
'ServerID' => is_numeric( $value ) ? $value : -1 ,
'Status' => is_numeric( $value ) ? 'Send OK.' : $value ,
];
}
return $result;
}
protected function createExtra( $category , $uniqueCode ): array
{
$extra [ 'is_admin' ] = $this->isAdmin;
$extra [ 'is_systematic' ] = $this->isSystematic;
$extra [ 'category' ] = $category;
$extra [ 'operator' ] = 'simcard';
$extra [ 'code' ] = $uniqueCode;
$extra [ 'messagePattern' ] = $this->messagePattern;
$extra [ 'className' ] = $this->collection->isEmpty() ? null : getNamespaceMap( $this->collection->first() );
return $extra;
}
private function setIsAdminAndIsSystematicInConfig(): void
{
$this->config[ 'is_admin' ] = $this->isAdmin;
$this->config[ 'is_systematic' ] = $this->isSystematic;
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Services\Notification\Events;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Queue\SerializesModels;
class SmsSent
{
use SerializesModels;
public Collection $collection;
public array $response;
public array $payload;
public array $extra;
/**
* Create a new event instance.
*
* @param Collection $collection
* @param array $response
* @param array $payload
* @param array $extra
*/
public function __construct( Collection $collection , array $response , array $payload , array $extra )
{
$this->collection = $collection;
$this->response = $response;
$this->payload = $payload;
$this->extra = $extra;
}
}
@@ -0,0 +1,36 @@
<?php
namespace App\Services\Notification\Events;
use App\Models\SmsBatch;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Queue\SerializesModels;
class SmsSentAgain
{
use SerializesModels;
public Collection $collection;
public array $response;
public array $payload;
public array $extra;
public SmsBatch $smsBatch;
/**
* Create a new event instance.
*
* @param Collection $collection
* @param array $response
* @param array $payload
* @param array $extra
* @param SmsBatch $smsBatch
*/
public function __construct( Collection $collection , array $response , array $payload , array $extra , SmsBatch $smsBatch )
{
$this->collection = $collection;
$this->response = $response;
$this->payload = $payload;
$this->extra = $extra;
$this->smsBatch = $smsBatch;
}
}
@@ -0,0 +1,52 @@
<?php
namespace App\Services\Notification\Listeners;
use App\Models\Sms;
use App\Models\SmsBatch;
use App\Services\Notification\Events\SmsSent;
use Illuminate\Support\Facades\Log;
class StoreSmsInDatabase
{
public function __construct()
{}
public function handle( SmsSent $event ): void
{
$chars_in_every_sms_part = config( "sms.sms_length_calculator.chars_in_every_sms_part" ) > 0 ? : 60;
$smsList = [];
foreach ( $event->collection as $key => $value ) {
$smsList[ $key ] = new Sms( [
'client_id' => $event->response[ $key ][ 'ClientID' ] ,
'status' => $event->response[ $key ][ 'Status' ] ,
'message' => $event->payload[ $key ][ 'Message' ] ,
'rel_id' => $value->id ,
'segment_count' => ceil( strlen( $event->extra[ 'messagePattern' ] ) / $chars_in_every_sms_part ) ,
'cell_number' => $event->payload[ $key ][ 'Cellphone' ] ,
'rel_type' => $event->extra[ 'className' ] ,
'fee' => $event->extra[ 'fee' ] ,
] );
}
Log::alert( 'store SmsBatch' , [ 'hasSms' => SmsBatch::where( 'code' , $event->extra[ 'code' ] )->first() ] );
$smsBatch = SmsBatch::firstOrCreate(
[
'code' => $event->extra[ 'code' ]
] ,
[
'category' => $event->extra[ 'category' ] ,
'operator' => $event->extra[ 'operator' ] ,
'type' => $event->extra[ 'type' ] ,
'pattern' => $event->extra[ 'messagePattern' ] ,
'is_admin' => $event->extra[ 'is_admin' ] ,
'is_systematic' => $event->extra[ 'is_systematic' ] ,
'from' => $event->extra[ 'from' ] ,
]
);
$smsBatch->smsList()->saveMany( $smsList );
}
}
@@ -0,0 +1,70 @@
<?php
namespace App\Services\Notification\MessagePattern;
use Illuminate\Database\Eloquent\Model;
class Pattern
{
protected string $pattern;
public function __construct( $pattern )
{
$this->pattern = $pattern;
}
public function fill( $model ): string
{
$replacements = $this->findReplacements( $model );
return strtr( $this->pattern , $replacements );
}
protected function findReplacements( $model , $prefix = '{' , $postfix = '}' ): array
{
$replacements = [];
foreach ( $model->messageFields as $field ) {
list( $nickName , $value ) = $this->getFieldValue( $model , $field );
$replacements[ $prefix . $nickName . $postfix ] = $value;
}
if ( config( 'notification.fields' ) ) {
foreach ( config( 'notification.fields' ) as $name => $field ) {
$replacements[ $prefix . $name . $postfix ] = $field;
}
}
return $replacements;
}
protected function getFieldValue( Model $model , string $messageField ): array
{
$parts = explode( ' as ' , $messageField );
if ( count( $parts ) == 2 and $this->isRelation( $parts[ 0 ] ) ) {
list( $relation , $field ) = $this->splitRelationField( $parts[ 0 ] );
$model->loadMissing( $relation );
$key = $parts[ 1 ];
$value = $model->$relation ? $model->$relation->$field : '';
} else {
$key = $messageField;
$value = $model->$messageField;
}
return [ $key , $value ];
}
protected function isRelation( $field ): bool
{
return str_contains( $field , ':' );
}
protected function splitRelationField( $field ): array
{
$parts = explode( ':' , $field );
$partsCount = count( $parts );
return [ implode( '.' , array_slice( $parts , 0 , $partsCount - 1 ) ) , $parts[ $partsCount - 1 ] ];
}
public function getPattern(): string
{
return $this->pattern;
}
}
@@ -0,0 +1,46 @@
<?php
namespace App\Services\Notification;
use App\Models\User;
class SendSmsToAdmins
{
protected array $mobiles;
public function __construct()
{
$this->mobiles = [
"09101526570",
"09128529050"
];
}
public function sendRequestNotification($device_title, $smsUser)
{
$adminCollection = User::query()
->orWhere('role', 'admin');
$adminText = "کاربر %s
با شماره ی همراه %s
درخواستی زیر را ثبت کرد\n
%s\n";
$adminText = sprintf($adminText, $smsUser->full_name, $smsUser->cell_number, $device_title);
SmsNotification::to($adminCollection)->isSystematic()->send(
$adminText,
'service'
);
$userText = "%s عزیز\n
درخواست شما را دریافت کردیم\n
به زودی همکاران ما با شما تماس خواهند گرفت\n
از اعتماد شما سپاسگزاریم\n";
$userText = sprintf($userText, $smsUser->full_name);
$userCollection = User::query()->where('id', $smsUser->id);
$res = SmsNotification::to($userCollection)->isSystematic()->send(
$userText,
'service'
);
}
}
@@ -0,0 +1,121 @@
<?php
namespace App\Services\Notification;
use App\Models\SmsBatch;
use App\Services\Notification\Batch\PeerToPeer;
use App\Services\Notification\Batch\SimCard;
use Illuminate\Support\Str;
class SmsNotification
{
protected $builder;
protected string $category;
protected $userData;
protected bool $isSystematic = false;
protected bool $isAdmin = false;
protected static $self = null;
private function __construct($builder, $userData)
{
$this->builder = $builder;
$this->userData = $userData;
$this->category = $this->builder->limit(2)->count() > 1 ? 'batch' : 'single';
}
public function setBuilder($builder): static
{
$this->builder = $builder;
$this->category = $this->builder->limit(2)->count() > 1 ? 'batch' : 'single';
return $this;
}
public function setUserData($userData): static
{
$this->userData = $userData;
return $this;
}
public static function to($builder, $userData = null)
{
if (static::$self === null) {
static::$self = new static($builder, $userData);
}
return static::$self;
}
public function isSystematic(): static
{
$this->isSystematic = true;
return $this;
}
public function isAdmin(): static
{
$this->isAdmin = true;
return $this;
}
public function sendAgain(SmsBatch $smsBatch): void
{
$uniqueCode = Str::random(40);
foreach ($this->chuncks() as $notification) {
switch ($smsBatch->type) {
case 'advertise':
(new PeerToPeer($smsBatch->pattern, $notification, $this->category, $uniqueCode))->isAdmin($this->isAdmin)->isSystematic($this->isSystematic)->sendAgain($this->userData,
$smsBatch);
break;
case 'simcard' :
(new SimCard($smsBatch->pattern, $notification, $this->category, $uniqueCode))->isAdmin($this->isAdmin)->isSystematic($this->isSystematic)->sendAgain($this->userData, $smsBatch);
break;
case 'service':
(new PeerToPeer($smsBatch->pattern, $notification, $this->category, $uniqueCode, 'service'))->isAdmin($this->isAdmin)->isSystematic($this->isSystematic)->sendAgain($this->userData,
$smsBatch);
break;
}
}
}
public function send($message, $method = 'advertise'): void
{
$uniqueCode = Str::random(40);
foreach ($this->chuncks() as $notification) {
switch ($method) {
case 'advertise':
(new PeerToPeer($message, $notification, $this->category, $uniqueCode))->isAdmin($this->isAdmin)->isSystematic($this->isSystematic)->send($this->userData);
break;
case 'simcard' :
(new SimCard($message, $notification, $this->category, $uniqueCode))->isAdmin($this->isAdmin)->isSystematic($this->isSystematic)->send($this->userData);
break;
case 'service':
(new PeerToPeer($message, $notification, $this->category, $uniqueCode, 'service'))->isAdmin($this->isAdmin)->isSystematic($this->isSystematic)->send($this->userData);
break;
}
}
}
public function sendWithTemplate($template): void
{
if ( ! is_null($template)) {
$this->send($template->template, $template->operator);
}
}
protected function chuncks(): \Generator
{
$limit = config('notification.max_phone_size.do_send_sms_array_c');
$iteration = 0;
while (true) {
$offset = $iteration * $limit;
$chunk = $this->builder->offset($offset)->limit($limit)->get();
if ($chunk->isEmpty()) {
break;
}
$iteration++;
yield $chunk;
}
}
}
+4 -1
View File
@@ -50,7 +50,10 @@
"Packages\\": "packages/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
"files": [
"app/Helpers/helpers.php"
]
},
"autoload-dev": {
"psr-4": {
+125
View File
@@ -0,0 +1,125 @@
<?php
use App\Models\Sms;
return [
'db_name' => 'willaengine',
'morph_models' => [],
/*
|--------------------------------------------------------------------------
| Default Driver
|--------------------------------------------------------------------------
|
| This value determines which of drivers should be used.
|
*/
'default' => 'advertise',
/*
|--------------------------------------------------------------------------
| Notification Configs
|--------------------------------------------------------------------------
|
| These are the list of configs to use for sending sms.
|
*/
'drivers' => [
'advertise' => [
'url' => 'http://188.0.240.110/class/sms/wsdlservice/server.php?wsdl',
'username' => env('SMS_USERNAME'),
'password' => env('SMS_PASSWORD'),
'from' => env('SMS_NUMBER_ADVERTISE'),
],
'service' => [
'url' => 'http://188.0.240.110/class/sms/wsdlservice/server.php?wsdl',
'username' => env('SMS_USERNAME'),
'password' => env('SMS_PASSWORD'),
'from' => env('SMS_NUMBER_SERVICE'),
],
'simcard' => [
'url' => 'http://188.0.240.110/class/sms/wsdlservice/server.php?wsdl',
'username' => env('SMS_USERNAME'),
'password' => env('SMS_PASSWORD'),
'from' => env('SMS_NUMBER_SIM_CARD'),
'fee' => 150
],
'pattern' => [
'url' => 'http://188.0.240.110/class/sms/wsdlservice/server.php?wsdl',
'username' => env('SMS_USERNAME'),
'password' => env('SMS_PASSWORD'),
'from' => env('SMS_NUMBER_SERVICE'),
],
'rahyab_advertise' => [
'url' => 'https://sms.igama.ir/webservice/sms.asmx?wsdl',
'username' => env('RAHYAB_SMS_USERNAME'),
'password' => env('RAHYAB_SMS_PASSWORD'),
'from' => env('RAHYAB_SMS_NUMBER_ADVERTISE'),
'fee' => 100
],
'rahyab_service' => [
'url' => 'https://sms.igama.ir/webservice/sms.asmx?wsdl',
'username' => env('RAHYAB_SMS_USERNAME'),
'password' => env('RAHYAB_SMS_PASSWORD'),
'from' => env('RAHYAB_SMS_NUMBER_SERVICE'),
'fee' => 80
],
],
/*
|--------------------------------------------------------------------------
| Class Maps
|--------------------------------------------------------------------------
|
| This is the array of Classes that maps to Drivers above.
|
*/
'map' => [
'advertise' => Sms::class,
'service' => Sms::class,
'simcard' => Sms::class,
'pattern' => SmsPattern::class,
'rahyab_advertise' => HelloWorld::class,
],
/*
|--------------------------------------------------------------------------
| Fields Pattern
|--------------------------------------------------------------------------
|
| This is the array of fields that used in sms patterns.
|
*/
'fields' => [
'time' => now('Asia/Tehran')->format('H:i:s'),
'date' => now('Asia/Tehran')->format('Y/m/d')
],
/*
|--------------------------------------------------------------------------
| MAXIMUM NUMBER OF PHONE NUMBERS IN ONE BATCH
|--------------------------------------------------------------------------
|
| CAUTION!! DONT TOUCH THESE NUMBERS
|
*/
'max_phone_size' => [
'do_send_sms' => 83,
'do_send_sms_array_c' => 100,
],
'max_update_devlivery_status_bulk_items' => 100,
'sms_length_calculator' => [
'encoding' => '8', //bit
'chars_in_every_sms_part' => 63
],
'config_system' => [],
];
+1 -1
View File
@@ -27,7 +27,7 @@ class ItemFactory extends Factory
'udi' => $this->faker->uuid,
'repair' => $this->faker->boolean,
'creator_id' => \App\Models\User::factory(),
'status' => $this->faker->randomElement(['approved', 'rejected', 'suspended']),
'status' => $this->faker->randomElement(['approved', 'rejected', 'pending']),
];
}
}
+1 -1
View File
@@ -24,7 +24,7 @@ class PackageFactory extends Factory
'bar_code' => $this->faker->optional()->word,
'qr_code' => $this->faker->optional()->word,
'creator_id' => User::factory(), // ایجاد کاربر دیگر به عنوان creator
'status' => $this->faker->randomElement(['approved', 'rejected', 'suspended']),
'status' => $this->faker->randomElement(['approved', 'rejected', 'pending']),
'created_at' => now(),
'updated_at' => now(),
];
@@ -22,7 +22,7 @@ class CreateTransfersTable extends Migration
$table->foreign('user_id')->references('id')->on('users');
$table->dateTime('from_date')->nullable();
$table->dateTime('to_date')->nullable();
$table->enum( 'status' , [ StatusTypeEnum::APPROVED , StatusTypeEnum::REJECTED , StatusTypeEnum::SUSPENDED ] )->default( StatusTypeEnum::SUSPENDED );
$table->enum( 'status' , [ StatusTypeEnum::APPROVED , StatusTypeEnum::REJECTED , StatusTypeEnum::PENDING ] )->default( StatusTypeEnum::PENDING );
$table->timestamps();
$table->softDeletes();
});
@@ -15,7 +15,7 @@ class UpdateItemsTable4 extends Migration
{
Schema::drop('item_package');
Schema::table('items', function (Blueprint $table) {
$table->unsignedBigInteger('package_id')->nullable()->after("id");
$table->unsignedBigInteger('package_id')->nullable()->after("id")->nullOnDelete();
});
}
@@ -18,7 +18,7 @@ class AddStatusToItemsTable extends Migration
$table->dropColumn( 'status' );
} );
Schema::table( 'items' , function ( Blueprint $table ) {
$table->enum( 'status' , [ StatusTypeEnum::APPROVED , StatusTypeEnum::REJECTED , StatusTypeEnum::SUSPENDED ] )->default( StatusTypeEnum::SUSPENDED );
$table->enum( 'status' , [ StatusTypeEnum::APPROVED , StatusTypeEnum::REJECTED , StatusTypeEnum::PENDING ] )->default( StatusTypeEnum::PENDING );
} );
}
@@ -18,7 +18,7 @@ class AddStatusToPackagesTable extends Migration
$table->dropColumn( 'verified' );
} );
Schema::table( 'packages' , function ( Blueprint $table ) {
$table->enum( 'status' , [ StatusTypeEnum::APPROVED , StatusTypeEnum::REJECTED , StatusTypeEnum::SUSPENDED ] )->default( StatusTypeEnum::SUSPENDED );
$table->enum( 'status' , [ StatusTypeEnum::APPROVED , StatusTypeEnum::REJECTED , StatusTypeEnum::PENDING ] )->default( StatusTypeEnum::PENDING );
} );
}
@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('labels', function (Blueprint $table) {
$table->boolean('enable')->default(true);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('labels', function (Blueprint $table) {
$table->dropColumn('enable');
});
}
};
@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('labels', function (Blueprint $table) {
$table->renameColumn('enable', 'enabled');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('labels', function (Blueprint $table) {
$table->renameColumn('enabled', 'enable');
});
}
};
@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('sms', function (Blueprint $table) {
$table->increments( 'id' );
$table->unsignedBigInteger( 'client_id' )->nullable();
$table->string( 'status' );
$table->string( 'message' , 100 );
$table->unsignedInteger( 'rel_id' );
$table->string( 'rel_type' , 50 );
$table->string( 'cell_number' , 20 );
$table->unsignedInteger( 'fee' )->default( 0 );
$table->unsignedInteger( 'sms_batch_id' );
$table->index( 'sms_batch_id' );
$table->integer( 'segment_count' )->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('sms');
}
};
@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('sms_batch', function (Blueprint $table) {
$table->increments( 'id' );
$table->string( 'category' );
$table->string( 'operator' , 100 );
$table->enum( 'type' , [ 'service' , 'simcard' , 'advertise' ] );
$table->string( 'code' , 40 );
$table->string( 'pattern' )->nullable();
$table->boolean( 'is_admin' )->default( 0 );
$table->boolean( 'is_systematic' )->default( 0 );
$table->string( 'from' )->nullable();
$table->softDeletes();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('sms_batch');
}
};
+1 -1
View File
@@ -15,7 +15,7 @@ class DatabaseSeeder extends Seeder
public function run()
{
$this->call([
TableSeeder::class
// FakerSeeder::class
]);
}
}
@@ -4,7 +4,7 @@ namespace Database\Seeders;
use Illuminate\Database\Seeder;
class TableSeeder extends Seeder
class FakerSeeder extends Seeder
{
/**
* Seed the application's database.
+75
View File
@@ -0,0 +1,75 @@
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
class TempSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run(): void
{
$roles = [
['name' => 'Admin','guard_name'=>'api'],
['name' => 'Supervisor','guard_name'=>'api'],
['name' => 'User','guard_name'=>'api']
];
Role::insert($roles);
$user = User::create([
'name' => 'user',
'email' => 'user@user',
'country_code' => '0098',
'cell_number' => '09392349878',
'gender' => 'Male',
'verified' => 'Verified',
'status' => 'Active',
'medical_center_id' => 1, // ایجاد مرکز پزشکی به طور خودکار
'password' => bcrypt('password'), // رمز عبور پیش‌فرض
'address' => 'yyop.st 45 5.No',
'remember_token' => '1234567891',
'created_at' => now(),
'updated_at' => now(),
]);
$admin = User::create([
'name' => 'admin',
'email' => 'admin@admin',
'country_code' => '0098',
'cell_number' => '09121231234',
'gender' => 'Male',
'verified' => 'Verified',
'status' => 'Active',
'medical_center_id' => 1, // ایجاد مرکز پزشکی به طور خودکار
'password' => bcrypt('password'), // رمز عبور پیش‌فرض
'address' => 'rgdforp.st 49 8.No',
'remember_token' => '5432123459',
'created_at' => now(),
'updated_at' => now(),
]);
$supervisor=User::create([
'name' => 'supervisor',
'email' => 'supervisor@supervisor',
'country_code' => '0098',
'cell_number' => '09101231232',
'gender' => 'Male',
'verified' => 'Verified',
'status' => 'Active',
'medical_center_id' => 1, // ایجاد مرکز پزشکی به طور خودکار
'password' => bcrypt('password'), // رمز عبور پیش‌فرض
'address' => 'yyhdfghop.st 43 6.No',
'remember_token' => '1234543212',
'created_at' => now(),
'updated_at' => now(),
]);
$user->assignRole('User');
$admin->assignRole('Admin');
$supervisor->assignRole('Supervisor');
}
}
+21
View File
@@ -0,0 +1,21 @@
server {
listen 80;
index index.php index.html;
server_name localhost;
root /var/www/html/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
+62
View File
@@ -0,0 +1,62 @@
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
image: cssd_app
container_name: cssd_app
env_file:
- .env
volumes:
- .:/var/www/html
depends_on:
- mysql
- redis
networks:
- cssd-network
nginx:
image: nginx:alpine
ports:
- "8089:80"
volumes:
- .:/var/www/html
- ./developement/nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
- mysql
networks:
- cssd-network
mysql:
image: 'docker-proxy.meshkee.com/mysql/mysql-server:8.0'
container_name: cssd_mysql
ports:
- "3312:3306"
environment:
MYSQL_ROOT_HOST: '%'
MYSQL_DATABASE: "${DB_DATABASE:-cssd}"
MYSQL_PORT: "${DB_PORT:-3306}"
MYSQL_USERNAME: "${DB_USERNAME:-root}"
MYSQL_PASSWORD: "${DB_PASSWORD:-secret}"
MYSQL_ROOT_PASSWORD: "${DB_PASSWORD:-secret}"
volumes:
- db_volume:/var/lib/mysql
networks:
- cssd-network
redis:
image: 'docker-proxy.meshkee.com/redis:alpine'
container_name: cssd_redis
ports:
- "6385:6379"
networks:
- cssd-network
volumes:
db_volume:
networks:
cssd-network:
driver: bridge
-17224
View File
File diff suppressed because it is too large Load Diff
+19 -12
View File
@@ -4,10 +4,12 @@ namespace Packages\Auth;
use App\Http\Controllers\Api\Auth\LoginController;
use App\Models\User;
use App\Services\Notification\SmsNotification;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Packages\Messaging\src\Facades\MessageResponse;
use Packages\SMSSender\SMSSender;
// use Packages\SMSSender\SMSSender;
trait SendsPasswordResetEmails
{
@@ -37,17 +39,15 @@ trait SendsPasswordResetEmails
*/
public function checkDisposablePassword(Request $request)
{
if ( \Cache::has($request->code) ) {
$userid = \Cache::pull($request->code);
$user = User::where('id', $userid)->first();
$userid = \Cache::pull($request->code);
if ( !is_null($userid) ) {
$user = User::findOrFail($userid);
if($user) {
$user->password = \Hash::make($request->code);
$user->save();
$password = rand(10000000, 999999999);
$user->password = \Hash::make($password);
$user->save();
$request->merge([ 'cell_number' => $user->cell_number, 'password' => $password ]);
return (new LoginController())->login($request);
$request->merge([ 'cell_number' => $user->cell_number, 'password' => $request->code ]);
return (new LoginController())->login($request);
}
return MessageResponse::error('User Not Found');
}
@@ -57,11 +57,18 @@ trait SendsPasswordResetEmails
protected function generateAndSendCode($request)
{
$user = User::where('cell_number', $request->cell_number)->where('status', 'Active')->first();
$userModel = User::where('cell_number', $request->cell_number)->where('status', 'Active');
$user = $userModel->first();
if ($user) {
$code = rand(100000, 999999);
\Cache::put($code, $user->id, Carbon::now()->addMinutes(30));
SMSSender::instance()->patternSend($request->cell_number, 'jqomyn42wo', ["verification-code" => $code]);
SmsNotification::to( $userModel )->isSystematic()->send(
trans( 'sms.reset_password' , [
'activation_code' => $code
] ) ,
'service'
);
// SMSSender::instance()->patternSend($request->cell_number, 'jqomyn42wo', ["verification-code" => $code]);
return MessageResponse::success('Send Disposable Password');
}
return MessageResponse::error('User Not Found');
+6 -3
View File
@@ -3,10 +3,14 @@ const urls = {
return `/ShowTestResult/${id}`;
},
showItem: function(id) {
return `/ShowItem/${id}`;
// return `/ShowItem/${id}`;
return `/api/show-item/${id}`;
},
showItemByUdi: function(udi) {
return `/api/show-item/udi/${udi}`;
},
showPackage: function(id) {
return `/ShowPackage/${id}`;
return `/api/show-package/${id}`;
},
showLabel: function(id) {
return `/ShowLabel/${id}`;
@@ -15,7 +19,6 @@ const urls = {
return `/ShowCycle/${id}`;
},
Barcode: function(code, type) {
console.log(code, type,'aaa');
return `/BarCode/${code}/${type}`;
},
packageBarcode: function(code) {
-1
View File
@@ -30,7 +30,6 @@ function route (options) {
}
Vue.use(Router)
console.log(paths);
// Create a new router
const router = new Router({
mode: 'history',
+44 -33
View File
@@ -5,37 +5,48 @@
*/
export default [
{
path: '/',
name: 'home',
view: 'Home/Intro',
// meta : {
// onlyWhenLoggedOut : true
// }
},
{
path: '/Show/Item/:item',
name: 'ShowItem',
view: 'Item/ShowItem'
},
{
path: '/Show/Package/:package',
name: 'ShowPackage',
view: 'Package/ShowPackage'
},
{
path: '/Show/Label/:label',
name: 'ShowLabel',
view: 'Label/ShowLabel'
},
{
path: '/Show/Cycle/:cycle',
name: 'ShowCycle',
view: 'Cycle/ShowCycle'
},
{
path: '/Show/TestResult/:id',
name: 'ShowTestResult',
view: 'TestResult/ShowTestResult'
},
{
path: '/',
name: 'home',
view: 'Home/Intro',
// meta : {
// onlyWhenLoggedOut : true
// }
},
{
path: '/Show/Item/:item',
name: 'ShowItem',
view: 'Item/ShowItem',
meta: {public: true}
},
{
path: '/Show/UDI/:udi',
name: 'ShowItem',
view: 'Item/ShowItem',
meta: {public: true}
},
{
path: '/Show/Package/:package',
name: 'ShowPackage',
view: 'Package/ShowPackage',
meta: { public: true }
},
{
path: '/Show/Label/:label',
name: 'ShowLabel',
view: 'Label/ShowLabel',
meta: { public: true }
},
{
path: '/Show/Cycle/:cycle',
name: 'ShowCycle',
view: 'Cycle/ShowCycle',
meta: { public: true }
},
{
path: '/Show/TestResult/:id',
name: 'ShowTestResult',
view: 'TestResult/ShowTestResult',
meta: { public: true }
},
]
+198 -117
View File
@@ -1,125 +1,184 @@
<template>
<v-container grid-list-xs>
<material-card color="black" title="Show Cycle">
<v-layout id="printMe" align-left justify-left wrap class="px-5 my-3">
<h3 class="ml-3">Cycle - {{ MedicalCenter }}</h3>
<material-card color="black" title="Show Cycle">
<v-layout align-left justify-left wrap id="printMe" class="px-3 my-3">
<h3 class="mt-0">
Cycle - {{ (data.user && data.user.medical_center) ? data.user.medical_center.name : "" }}
</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="ml-4">
<v-flex xs12 md6 sm6>
<div class="WM-d-flex">
<span class="title">Cycle ID :</span>
<span class="headline ml-1" style="letter-spacing:0 !important">{{ data.id }}</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div>
<span class="title">Sterilizer ID :</span>
<span class="headline ml-1" style="letter-spacing:0 !important">{{ data.sterilizer_id }}</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class="WM-d-flex">
<v-icon class="WMi-user"></v-icon>
<span class="headline ml-2" style="letter-spacing:0 !important">{{ data.user ? data.user.name : '' }}</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class="WM-d-flex">
<span class="title">Cycle Number :</span>
<span class="headline ml-2" style="letter-spacing:0 !important">{{ data.cycle_number }}</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class="WM-d-flex">
<v-icon class="WMi-Industry"></v-icon>
<span class="headline ml-2" style="letter-spacing:0 !important">{{ data.date }}</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class="WM-d-flex">
<v-icon class="WMi-pencil"></v-icon>
<span class="headline ml-1" style="letter-spacing:0 !important">{{ data.note }}</span>
</div>
</v-flex>
</v-layout>
<v-layout align-left justify-left wrap class="px-5 my-3">
<h3 class="ml-3">Barcode And QRCode Image</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="ml-4">
<v-flex xs12 md6 sm6 v-if="barcodeimg">
<img :src="barcodeimg" class="WM-Width-350"><br />
<span>Cycle ID : {{data.id}}</span>
</v-flex>
</v-layout>
<v-layout row wrap class="ml-4">
<v-flex xs12 md6 sm6 v-if="QRCodeimg">
<img :src="QRCodeimg" class="WM-Width-150">
</v-flex>
</v-layout>
</v-layout>
</v-layout>
<v-layout align-left justify-left wrap class="px-5 my-3">
<h3 class="ml-3">Labels</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
<v-layout row wrap class="">
<v-flex xs12 sm6 md4>
<div>
<span class="title">Cycle ID :</span>
<span class="headline ml-1" style="letter-spacing:0 !important">{{ data.id }}</span>
</div>
</v-flex>
<v-flex xs12 sm6 md4>
<div>
<span class="title">Sterilizer ID :</span>
<span class="headline ml-1"
style="letter-spacing:0 !important">{{ data.sterilizer_id }}</span>
</div>
</v-flex>
<v-flex xs12 sm6 md4>
<div class="WM-d-flex">
<v-icon class="WMi-user"/>
<span class="headline ml-2"
style="letter-spacing:0 !important">{{ data.user ? data.user.name : '' }}</span>
</div>
</v-flex>
<v-flex xs12 sm6 md4>
<div>
<span class="title">Cycle Number :</span>
<span class="headline ml-2"
style="letter-spacing:0 !important">{{ data.cycle_number }}</span>
</div>
</v-flex>
<v-flex xs12 sm6 md4>
<div class="WM-d-flex">
<v-icon class="WMi-Industry"/>
<span class="headline ml-2" style="letter-spacing:0 !important">{{ data.date }}</span>
</div>
</v-flex>
<v-flex xs12 sm6 md4>
<div class="WM-d-flex">
<v-icon class="WMi-pencil"/>
<span class="headline ml-1" style="letter-spacing:0 !important">{{ data.note }}</span>
</div>
</v-flex>
</v-layout>
</v-flex>
</v-layout>
<v-layout row wrap style="margin-left: 20px !important;">
<v-flex xs12>
<v-layout row wrap class="my-3">
<h3 class="mt-0">Barcode And QRCode Image</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="align-center mt-3">
<v-flex xs12 md6 sm6 v-if="barcodeimg">
<img :src="barcodeimg" class="barcode-container"><br/>
<span>Cycle ID : {{ data.id }}</span>
</v-flex>
<template>
<v-expansion-panel class="WM-Panel" v-for="(label, key) in data.labels" :key="key">
<v-expansion-panel-content>
<template v-slot:header>
<div>{{ label.id }} ({{ label.pivot.count }})</div>
</template>
<v-card>
<v-card-text> Package :
<v-expansion-panel class="WM-Panel">
<v-expansion-panel-content>
<template v-slot:header>
<div>{{ label.package.name }} </div>
</template>
<v-card>
<v-card-text>note : {{ label.package.note }}</v-card-text>
<v-card-text>
Items :
<v-expansion-panel class="WM-Panel" v-for="item in label.package.items" :key="item.key">
<v-flex xs12 md6 sm6 v-if="QRCodeimg" class="WM-Align-R">
<a :href="'https://www.cssd-doc.com/Show/Cycle/'+data.id+''" target="_blank">
<img :src="QRCodeimg" class="WM-Width-150">
</a>
</v-flex>
</v-layout>
</v-layout>
</v-flex>
<v-flex xs12 v-if="data.labels && data.labels.length">
<v-layout row wrap class="my-3">
<h3 class="mt-0">Labels</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap>
<template>
<v-expansion-panel class="WM-Panel" v-for="(label, key) in data.labels" :key="key">
<v-expansion-panel-content>
<template v-slot:header>
<v-layout row wrap class="CSSD-font">
<span class="item-counter">{{ key + 1 }}</span>
<v-layout row wrap class="pl-2">
<v-flex xs12 sm6 md6>
<span class="sub-text">Label ID:</span>
{{label.id}}
</v-flex>
<v-flex xs12 sm6 md6>
<span class="sub-text">Label Pivot counter:</span>
{{ label.pivot.count }}
</v-flex>
</v-layout>
</v-layout>
</template>
<v-card>
<v-card-text class="pa-0 pl-sm-3" v-if="label.package">
Package :
<template>
<v-expansion-panel class="WM-Panel">
<v-expansion-panel-content>
<template v-slot:header>
<div>{{ item.name }} ({{ item.pivot.count }})</div>
<v-layout row wrap class="CSSD-font">
<span class="item-counter">{{ key + 1 }}</span>
<v-layout row wrap class="pl-2">
<v-flex xs12 sm6 md6>
<span class="sub-text">Package ID:</span>
{{label.package.id}}
</v-flex>
<v-flex xs12 sm6 md6>
<span class="sub-text">Package Name:</span>
{{ label.package.name }}
</v-flex>
</v-layout>
</v-layout>
</template>
<v-card>
<v-card-text>note : {{ item.note }}</v-card-text>
<v-card-text class="pa-0 pl-sm-3">
note : {{label.package.note }}
</v-card-text>
<v-card-text class="pa-0 pl-sm-3"
v-if="label.package && label.package.items && label.package.items.length">
Items :
<v-expansion-panel class="WM-Panel"
v-for="(item, key) in label.package.items"
:key="key">
<v-expansion-panel-content>
<template v-slot:header>
<v-layout row wrap class="CSSD-font">
<span class="item-counter">{{ key + 1 }}</span>
<v-layout row wrap class="pl-2">
<v-flex xs12 sm4 md4>
<span class="sub-text">Item ID:</span>
{{ item.id }}
</v-flex>
<v-flex xs12 sm4 md4>
<span class="sub-text">Item Name:</span>
{{ item.name }}
</v-flex>
<v-flex xs12 sm4 md4 class="WM-Align-R">
<span v-if="item.pivot">
({{ item.pivot.count }})
</span>
</v-flex>
</v-layout>
</v-layout>
</template>
<v-card>
<v-card-text>note : {{ item.note }}
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</template>
</template>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</template>
</v-layout>
</v-layout>
</v-flex>
</v-layout>
<v-layout row wrap align-center justify-center style="text-align:center">
<v-flex class xs12 md12 sm12 >
<v-flex class xs12 md12 sm12>
<v-btn class="WM-NoShadow WM-Outline-Btn WM-Border WM-Border-Black" @click="addCycle()">
<v-icon class="black--text">keyboard_arrow_left</v-icon>
<span class="black--text">Back</span>
</v-btn>
<v-btn class="WM-CyanBlueGradient-BG" @click="print" style="padding:10px 60px">
<v-btn class="WM-CyanBlueGradient-BG" @click="print" style="padding:10px 60px">
<v-icon class="white--text mr-2 caption">fas fa-print</v-icon>
<span class="white--text">Print</span>
</v-btn>
@@ -136,35 +195,36 @@
<script>
import axios from "axios";
import { urls } from "@show/config/urls";
import {urls} from "@show/config/urls";
export default {
data: () => ({
data : {},
barcodeimg : '',
QRCodeimg : '',
MedicalCenter : ''
data: {},
barcodeimg: '',
QRCodeimg: '',
MedicalCenter: ''
}),
methods: {
async load(id) {
const result = await axios.get(urls.showCycle(id));
if (result.status == 200) {
this.data = result.data.data;
const result = await axios.get(urls.showCycle(id));
if (result.status == 200) {
this.data = result.data.data;
this.generateBarcode(this.data.id);
this.MedicalCenter = this.data.user.medical_center.name;
}
},
}
},
async generateBarcode(cycleId) {
const result = await axios.post(urls.Barcode(cycleId, 'Cycle'));
if (result && result.status == 200) {
this.QRCodeimg = result.data.data.QRCode ? result.data.data.QRCode : null;
this.barcodeimg = result.data.data.Barcode ? result.data.data.Barcode : null;
this.QRCodeimg = result.data.data.QRCode ? result.data.data.QRCode : null;
this.barcodeimg = result.data.data.Barcode ? result.data.data.Barcode : null;
}
},
editCycle(cycleId){
window.location.href = '/cycle/'+cycleId+'/edit';
editCycle(cycleId) {
window.location.href = '/cycle/' + cycleId + '/edit';
},
addCycle(cycleId){
addCycle(cycleId) {
window.location.href = '/add-cycle';
},
print() {
@@ -203,9 +263,30 @@ export default {
},
created() {
if (this.$route.params.cycle) {
this.load(this.$route.params.cycle);
}
this.load(this.$route.params.cycle);
}
},
};
</script>
<style scoped lang="scss">
.barcode-container {
width: 100%;
max-width: 290px;
}
.item-counter {
font-size: 44px;
opacity: .3;
font-family: 'Montserrat-Bold';
line-height: 44px;
position: absolute;
left: 0;
top: 0;
color: #b7b7b7;
}
.sub-text {
font-size: 12px;
}
</style>
+144 -63
View File
@@ -1,75 +1,112 @@
<template>
<v-container grid-list-xs>
<material-card color="black" title="Show Item">
<v-layout align-left id="printMe" justify-left wrap class="px-5 my-3">
<v-layout align-left id="printMe" justify-left wrap class="my-3">
<h3 class="ml-3 CSSD-font"> Item - {{ MedicalCenter }}</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="ml-4">
<v-layout row wrap class="ml-4 align-center">
<v-flex xs12 md6 sm6>
<div class>
<span class="title CSSD-font">Item ID :</span>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">{{ data.id }}</span>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">
{{ data.id }}
</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class>
<span class="title CSSD-font">Name :</span>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">{{ data.name }}</span>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">
{{ data.name }}
</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class>
<span class="title CSSD-font">Size :</span>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">{{ data.size }}</span>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">
{{ data.size }}
</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class>
<span class="title CSSD-font">UDI :</span>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">
{{ data.udi }}
</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class>
<span class="title CSSD-font">Specific :</span>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">{{ data.specific }}</span>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">
{{ data.specific }}
</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class>
<span class="title CSSD-font">Register User :</span>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">{{ data.user ? data.user.name : '' }}</span>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">
{{ data.user ? data.user.name : '' }}
</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class>
<span class="title CSSD-font">Date Register:</span>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">{{ data.created_at }}</span>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">
{{ data.created_at }}
</span>
</div>
</v-flex>
</v-layout>
<v-layout align-left justify-left wrap class="px-5 my-3">
<v-layout align-left justify-left row wrap class="my-3" v-if="data.files && data.files.length">
<h3 class="CSSD-font">Image</h3>
<v-flex xs12>
<hr class="v-divider theme--light"/>
</v-flex>
<v-layout row wrap class="mt-3">
<v-flex xs6 md2 sm2 v-for="(file, key) in data.files" :key="key">
<template v-if="file.file_type == 'document'">
<a target="_blank" :href="'/'+file.thumbnail">
<v-icon class="mr-2 caption">fas fa-check</v-icon>
{{ file.file_name }}</a>
</template>
<template v-else>
<img :src="file.thumbnail" style="width: 100%" @click="openLightbox(key)"/>
</template>
</v-flex>
</v-layout>
</v-layout>
<v-flex xs12></v-flex>
<v-layout align-left justify-left row wrap class="my-3">
<h3 class="ml-3 CSSD-font">Barcode And QRCode Image</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="ml-4">
<v-layout row wrap class="ml-4 align-center mt-2">
<v-flex xs12 md6 sm6 v-if="barcodeimg">
<img :src="barcodeimg" class="WM-Width-350"><br />
<span class="CSSD-font">Item ID : {{data.id}}</span>
<img :src="barcodeimg" class="barcode-container"><br/>
<span class="CSSD-font">Item ID : {{ data.id }}</span>
</v-flex>
</v-layout>
<v-layout row wrap class="ml-4">
<v-flex xs12 md6 sm6 v-if="QRCodeimg">
<v-flex xs12 md6 sm6 v-if="QRCodeimg" class="WM-Align-C">
<img :src="QRCodeimg" class="WM-Width-150">
</v-flex>
</v-layout>
</v-layout>
</v-layout>
<v-layout row wrap align-center justify-center style="text-align:center">
<v-flex class xs12 md12 sm12 >
<v-flex class xs12 md12 sm12>
<v-btn class="WM-NoShadow WM-Outline-Btn WM-Border WM-Border-Black" @click="addItem()">
<v-icon class="black--text">keyboard_arrow_left</v-icon>
<span class="black--text">Back</span>
</v-btn>
<v-btn class="WM-CyanBlueGradient-BG" @click="print" style="padding:10px 60px">
<v-btn class="WM-CyanBlueGradient-BG" @click="print" style="padding:10px 60px">
<v-icon class="white--text mr-2 caption">fas fa-print</v-icon>
<span class="white--text">Print</span>
</v-btn>
@@ -80,49 +117,85 @@
</v-flex>
</v-layout>
</material-card>
<vue-image-lightbox
v-if="showLightbox"
:media="lightboxImages"
:index="lightboxIndex"
@close="showLightbox = false"
/>
</v-container>
</template>
<script>
export default {
data: () => ({
data: {}
})
};
</script>
<script>
import { urls } from "@show/config/urls";
import {urls} from "@show/config/urls";
import axios from "axios";
import toast from "@/services/global/toast.service";
import VueImageLightbox from "vue-image-lightbox";
import 'vue-image-lightbox/dist/vue-image-lightbox.min.css'
export default {
data: () => ({
data : {},
QRCodeimg : '',
barcodeimg : '',
MedicalCenter : ''
data: {},
QRCodeimg: '',
barcodeimg: '',
MedicalCenter: '',
showLightbox: false,
lightboxIndex: 0,
lightboxImages: [],
}),
components: {
VueImageLightbox,
},
computed: {
imagesOnly() {
return this.data.files && this.data.files.length ? this.data.files.filter(file => file.file_type !== 'document') : [];
},
},
methods: {
async load(id) {
const result = await axios.get(urls.showItem(id));
if (result.status == 200) {
this.data = result.data.data;
this.generateBarcode(this.data.id);
this.MedicalCenter = this.data.user.medical_center.name;
}
},
async generateBarcode(itemId) {
const result = await axios.post(urls.Barcode(itemId, 'Item'));
if (result && result.status == 200) {
this.QRCodeimg = result.data.data.QRCode ? result.data.data.QRCode : null;
this.barcodeimg = result.data.data.Barcode ? result.data.data.Barcode : null;
try {
const result = await axios.get(urls.showItem(id));
if (result.status == 200) {
this.data = result.data.data;
if (this.data) {
this.generateBarcode(this.data);
this.MedicalCenter = this.data.user.medical_center.name;
}
}
} catch (error) {
console.error("Error loading data:", error);
}
},
editItem(itemId){
window.location.href = '/item/'+itemId+'/edit';
async loadByUdi(udi) {
try {
const result = await axios.get(urls.showItemByUdi(udi));
if (result.status == 200) {
this.data = result.data.data;
if (this.data) {
this.generateBarcode(this.data);
this.MedicalCenter = this.data.user.medical_center.name;
}
}
} catch (error) {
console.error("Error loading data:", error);
}
},
addItem(){
async generateBarcode(item) {
let code = item.udi;
if (code) {
const result = await axios.post(urls.Barcode(code, 'Item'));
if (result && result.status == 200) {
this.QRCodeimg = result.data.data.QRCode ? result.data.data.QRCode : null;
this.barcodeimg = result.data.data.Barcode ? result.data.data.Barcode : null;
}
} else {
toast.error('An error occurred while generating the barcode . please first set UDI');
}
},
editItem(itemId) {
window.location.href = '/item/' + itemId + '/edit';
},
addItem() {
window.location.href = '/add-item';
},
print() {
@@ -143,30 +216,38 @@ export default {
"left=0,top=0,width=800,height=900,toolbar=0,scrollbars=0,status=0"
);
WinPrint.document.write(`<!DOCTYPE html>
<html>
<head>
${stylesHtml}
</head>
<body>
${prtHtml}
</body>
</html>`);
WinPrint.document.write(`<!DOCTYPE html><html><head>${stylesHtml}</head><body> ${prtHtml}</body></html>`);
WinPrint.document.close();
WinPrint.focus();
WinPrint.print();
WinPrint.close();
},
openLightbox(index) {
this.lightboxIndex = index;
this.showLightbox = false;
this.$nextTick(() => {
this.showLightbox = true;
});
}
},
created() {
if (this.$route.params.item) {
// console.log(this.$route.params.item);
this.load(this.$route.params.item);
}
this.load(this.$route.params.item);
} else if (this.$route.params.udi) {
this.loadByUdi(this.$route.params.udi);
}
this.lightboxImages = this.imagesOnly && this.imagesOnly.length ? this.imagesOnly.map(file => ({
src: file.thumbnail,
thumb: file.thumbnail,
})) : [];
},
// mounted() {
// this.generateBarcode(this.data.id);
// }
};
</script>
<style scoped lang="scss">
.barcode-container {
width: 100%;
max-width: 290px;
}
</style>
+230 -164
View File
@@ -1,195 +1,235 @@
<template>
<v-container grid-list-xs>
<material-card color="black" title="Show Label">
<v-layout align-left justify-left wrap class="px-2 my-3">
<h3 class="ml-3">Label</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout id="printMe">
<v-flex xs12 md12 sm12>
<!-- ________ row1::Begin ________ -->
<v-layout row wrap>
<!-- ________ Column1::Begin ________ -->
<v-flex xs6 md6 sm6>
<v-layout row wrap class="ml-4">
<v-flex xs12 md12 sm12>
<div class="WM-d-flex">
<span class="headline ml-1 mb-1" style="letter-spacing:0 !important">{{ MedicalCenter }}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12 class="">
<div class="WM-d-flex">
<v-icon class="WMi-location"></v-icon>
<span class="headline ml-1 mb-1" style="letter-spacing:0 !important" v-if="dataLoaded">{{data.package.name}}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class="WM-d-flex">
<v-icon class="WMi-Industry"></v-icon>
<span class="headline ml-2 mb-1" style="letter-spacing:0 !important">{{ data.sterile_date }}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class="WM-d-flex">
<v-icon class="WMi-hourglass"></v-icon>
<span class="headline ml-2 mb-1" style="letter-spacing:0 !important">{{ data.expire_date }}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class="WM-d-flex">
<v-icon class="WMi-user"></v-icon>
<span class="headline ml-2 mb-1" style="letter-spacing:0 !important">{{ data.user ? data.user.name : '' }}</span>
</div>
</v-flex>
</v-layout>
</v-flex>
<!-- ________ Column1::End ________ -->
<!-- ________ Column2::Begin ________ -->
<v-flex xs6 md6 sm6>
<v-layout row wrap class="">
<v-flex xs12 md12 sm12>
<div>
<v-flex xs6 md6 sm6 v-if="QRCodeimg">
<a :href="'/Show/Package/'+data.package.id+''" target="_blank"><img :src="QRCodeimg" class="WM-Width-120"></a>
</v-flex>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class>
<span class="title">Sterilizer ID :</span>
<span class="headline ml-1 mb-1" style="letter-spacing:0 !important">{{ data.sterilizer_id}}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class>
<span class="title">Cycle No :</span>
<span class="headline ml-2 mb-1" style="letter-spacing:0 !important">{{ data.cycle_number }}</span>
</div>
</v-flex>
</v-layout>
</v-flex>
<!-- ________ Column2::End ________ -->
</v-layout>
<!-- ________ row1::Begin ________ -->
<v-container grid-list-xs>
<material-card color="black" title="Show Label">
<v-layout align-left justify-left wrap class="px-2 my-3">
<h3 class="ml-3">Label</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout id="printMe">
<v-flex xs12 md12 sm12>
<!-- ________ row1::Begin ________ -->
<v-layout row wrap>
<!-- ________ Column1::Begin ________ -->
<v-flex xs12 md6 sm6>
<v-layout row wrap class="">
<v-flex xs12 md12 sm12>
<div class="WM-d-flex">
<span class="headline ml-1 mb-1" style="letter-spacing:0 !important">
{{ MedicalCenter }}
</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12 class="">
<div class="WM-d-flex">
<v-icon class="WMi-location"/>
<span class="headline ml-1 mb-1" style="letter-spacing:0 !important"
v-if="dataLoaded">{{ data.package.name }}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class="WM-d-flex">
<v-icon class="WMi-Industry"/>
<span class="headline ml-2 mb-1"
style="letter-spacing:0 !important">{{ data.sterile_date }}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class="WM-d-flex">
<v-icon class="WMi-hourglass"/>
<span class="headline ml-2 mb-1"
style="letter-spacing:0 !important">{{ data.expire_date }}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class="WM-d-flex">
<v-icon class="WMi-user"/>
<span class="headline ml-2 mb-1" style="letter-spacing:0 !important">
{{ data.user ? data.user.name : '' }}
</span>
</div>
</v-flex>
</v-layout>
</v-flex>
<!-- ________ Column1::End ________ -->
<!-- ________ Column2::Begin ________ -->
<v-flex xs12 md6 sm6>
<v-layout row wrap class="mt-4">
<v-flex xs12 md12 sm12>
<div>
<v-flex xs6 md6 sm6 v-if="QRCodeimg">
<a :href="'/Show/Package/'+data.package.id+''" target="_blank">
<img :src="QRCodeimg" class="WM-Width-120">
</a>
</v-flex>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class>
<span class="headline">Sterilizer ID :</span>
<span class="title ml-1 mb-1"
style="letter-spacing:0 !important">{{ data.sterilizer_id }}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class>
<span class="headline">Cycle No :</span>
<span class="title ml-2 mb-1"
style="letter-spacing:0 !important">{{ data.cycle_number }}</span>
</div>
</v-flex>
</v-layout>
</v-flex>
<!-- ________ Column2::End ________ -->
</v-layout>
<!-- ________ row1::Begin ________ -->
<!-- ________ row2::Begin ________ -->
<v-layout row wrap>
<v-flex xs12 md12 sm12>
<div class="mt-4" style="text-align:center">
<v-layout row wrap>
<v-flex xs12 md12 sm12 v-if="barcodeimg">
<img :src="barcodeimg" class="barcode-container"><br/>
<span class="WM-Font-14">Lebel ID :</span>
<span>{{ data.id }}</span>
</v-flex>
</v-layout>
</div>
</v-flex>
</v-layout>
<!-- ________ row2::End ________ -->
<v-layout wrap row v-if="dataLoaded">
<h3 class="ml-3">Package</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="mx-sm-3">
<template>
<v-expansion-panel class="WM-Panel">
<v-expansion-panel-content>
<template v-slot:header>
<v-layout row wrap class="CSSD-font">
<span class="item-counter">{{ key + 1 }}</span>
<v-layout row wrap class="pl-2">
<v-flex xs12 sm6 md6>
<span class="sub-text">Package ID:</span>
{{data.package.id}}
</v-flex>
<v-flex xs12 sm6 md6>
<span class="sub-text">Package Name:</span>
{{ data.package.name }}
</v-flex>
</v-layout>
</v-layout>
</template>
<v-card>
<v-card-text>note : {{ data.package.note }}</v-card-text>
<v-card-text class="pa-0 pl-sm-3"
v-if="data.package && data.package.items && data.package.items.length">
Items :
<v-expansion-panel class="WM-Panel"
v-for="(item, key) in data.package.items"
:key="key">
<v-expansion-panel-content>
<template v-slot:header>
<v-layout row wrap class="CSSD-font">
<span class="item-counter">{{ key + 1 }}</span>
<!-- ________ row2::Begin ________ -->
<v-layout row wrap>
<v-flex xs12 md12 sm12>
<div class="mt-4" style="text-align:center">
<v-layout row wrap>
<v-flex xs6 md12 sm12 v-if="barcodeimg">
<img :src="barcodeimg" class="WM-Width-350"><br />
<span>{{data.id}}</span>
<v-layout row wrap class="pl-2">
<v-flex xs12 sm4 md4>
<span class="sub-text">Item ID:</span>
{{ item.id }}
</v-flex>
<v-flex xs12 sm4 md4>
<span class="sub-text">Item Name:</span>
{{ item.name }}
</v-flex>
<v-flex xs12 sm4 md4 class="WM-Align-R">
<span v-if="item.pivot">
({{ item.pivot.count }})
</span>
</v-flex>
</v-layout>
</v-layout>
</template>
<v-card>
<v-card-text>note : {{ item.note }}</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</template>
</v-layout>
</v-layout>
</v-flex>
</v-layout>
</div>
</v-flex>
</v-layout>
</v-layout>
<!-- ________ row2::End ________ -->
</v-flex>
</v-layout>
</v-layout>
<v-layout align-left justify-left wrap class="px-2 my-3" v-if="dataLoaded">
<h3 class="ml-3">Package</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="mx-3">
<template>
<v-expansion-panel class="WM-Panel">
<v-expansion-panel-content>
<template v-slot:header>
<div>{{ data.package.name }}</div>
</template>
<v-card>
<v-card-text>note : {{ data.package.note }}</v-card-text>
<v-card-text> Items :
<v-expansion-panel class="WM-Panel" v-for="item in data.package.items" :key="item.key">
<v-expansion-panel-content>
<template v-slot:header>
<div>{{ item.name }} ({{ item.pivot.count }})</div>
</template>
<v-card>
<v-card-text>note : {{ item.note }}</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</template>
</v-layout>
</v-layout>
<v-layout row wrap align-center justify-center style="text-align:center">
<v-flex class xs12 md12 sm12 >
<v-btn class="WM-NoShadow WM-Outline-Btn WM-Border WM-Border-Black" @click="addLabel()">
<v-icon class="black--text">keyboard_arrow_left</v-icon>
<span class="black--text">Back</span>
</v-btn>
<v-btn class="WM-CyanBlueGradient-BG" @click="print" style="padding:10px 60px">
<v-icon class="white--text mr-2 caption">fas fa-print</v-icon>
<span class="white--text">Print</span>
</v-btn>
<v-btn color="orange" class="mr-2" style="padding:10px 60px" @click="editLabel(data.id)">
<v-icon class="white--text mr-1 caption">fas fa-pen</v-icon>
<span>Edit</span>
</v-btn>
</v-flex>
</v-layout>
</material-card>
</v-container>
<v-layout row wrap align-center justify-center style="text-align:center">
<v-flex class xs12 md12 sm12>
<v-btn class="WM-NoShadow WM-Outline-Btn WM-Border WM-Border-Black" @click="goToAddLabel()">
<v-icon class="black--text">keyboard_arrow_left</v-icon>
<span class="black--text">Back</span>
</v-btn>
<v-btn class="WM-CyanBlueGradient-BG" @click="print" style="padding:10px 60px">
<v-icon class="white--text mr-2 caption">fas fa-print</v-icon>
<span class="white--text">Print</span>
</v-btn>
<v-btn color="orange" class="mr-2" style="padding:10px 60px" @click="editLabel(data.id)">
<v-icon class="white--text mr-1 caption">fas fa-pen</v-icon>
<span>Edit</span>
</v-btn>
</v-flex>
</v-layout>
</material-card>
</v-container>
</template>
<style media="screen">
.WM-d-flex{
display: flex;
}
</style>
<script>
import axios from "axios";
import { urls } from "@show/config/urls";
import {urls} from "@show/config/urls";
export default {
data: () => ({
data : {},
QRCodeimg : '',
barcodeimg : '',
MedicalCenter : '',
dataLoaded : false
data: {},
QRCodeimg: '',
barcodeimg: '',
MedicalCenter: '',
dataLoaded: false
}),
methods: {
async load(id) {
const result = await axios.get(urls.showLabel(id));
const result = await axios.get(urls.showLabel(id));
if (result.status == 200) {
this.data = result.data.data;
if (result.status == 200) {
this.data = result.data.data;
this.generateBarcode(this.data.id);
this.generateQRcodePackage(this.data.package.id);
this.MedicalCenter = this.data.user.medical_center.name;
this.dataLoaded = true;
}
},
}
},
async generateQRcodePackage(packageId) {
const result = await axios.post(urls.packageQRCode(packageId));
if (result && result.status == 200) {
this.QRCodeimg = result.data.data.QRCode ? result.data.data.QRCode : null;
this.QRCodeimg = result.data.data.QRCode ? result.data.data.QRCode : null;
}
},
async generateBarcode(labelId) {
const result = await axios.post(urls.Barcode(labelId, 'Label'));
if (result && result.status == 200) {
this.barcodeimg = result.data.data.Barcode ? result.data.data.Barcode : null;
this.barcodeimg = result.data.data.Barcode ? result.data.data.Barcode : null;
}
},
editLabel(LabelId){
window.location.href = '/label/'+LabelId+'/edit';
editLabel(LabelId) {
window.location.href = '/label/' + LabelId + '/edit';
},
addLabel(LabelId){
goToAddLabel(LabelId) {
window.location.href = '/add-label';
},
print() {
@@ -228,10 +268,36 @@ export default {
},
created() {
if (this.$route.params.label) {
console.log(this.$route.params);
this.load(this.$route.params.label);
}
this.load(this.$route.params.label);
}
},
};
</script>
<style media="screen">
.WM-d-flex {
display: flex;
}
</style>
<style scoped lang="scss">
.barcode-container {
width: 100%;
max-width: 290px;
}
.item-counter {
font-size: 44px;
opacity: .3;
font-family: 'Montserrat-Bold';
line-height: 44px;
position: absolute;
left: 0;
top: 0;
color: #b7b7b7;
}
.sub-text {
font-size: 12px;
}
</style>
+143 -99
View File
@@ -1,87 +1,116 @@
<template>
<v-container grid-list-xs>
<material-card color="black" title="Show Package">
<v-layout id="printMe" align-left justify-left wrap class="px-5 my-3">
<h3 class="ml-3 CSSD-font">Package - {{ MedicalCenter }}</h3>
<material-card color="black" title="Show Package">
<v-layout id="printMe" align-left justify-left wrap class="px-3 mb-3">
<h3 class="CSSD-font mt-0">
{{ data.name }} - MC
{{ (data.user != null && data.user.medical_center != null) ? data.user.medical_center.name : '' }}
</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="ml-4">
<v-flex xs12 md6 sm6>
<div class="WM-d-flex">
<v-icon class="WMi-info"></v-icon>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">{{ data.name }}</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class="WM-d-flex">
<v-icon class="WMi-Industry"></v-icon>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">{{ data.created_at }}</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class="WM-d-flex">
<v-icon class="WMi-user"></v-icon>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">{{ data.user ? data.user.name : '' }}</span>
</div>
</v-flex>
<v-flex xs12 md6 sm6>
<div class="WM-d-flex">
<v-icon class="WMi-pencil"></v-icon>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">{{ data.note }}</span>
</div>
</v-flex>
</v-layout>
<v-layout align-left justify-left wrap class="px-5 my-3">
<h3 class="ml-3 CSSD-font">Barcode And QRCode Image</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="ml-4">
<v-flex xs12 md6 sm6 v-if="barcodeimg">
<img :src="barcodeimg" class="WM-Width-350"><br />
<span class="CSSD-font">Package ID : {{data.id}}</span>
</v-flex>
</v-layout>
<v-layout row wrap class="ml-4">
<v-flex xs12 md6 sm6 v-if="QRCodeimg">
<img :src="QRCodeimg" class="WM-Width-150">
</v-flex>
</v-layout>
</v-layout>
</v-layout>
<v-layout align-left justify-left wrap class="px-5 my-3">
<h3 class="ml-3 CSSD-font">Items</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
<v-layout align-left justify-left wrap class="pt-3">
<v-flex xs12 sm4 md4>
<div class="WM-d-flex">
<v-icon class="WMi-info"/>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">
{{ data.name }}
</span>
</div>
</v-flex>
<v-flex xs12 sm4 md4>
<div class="WM-d-flex">
<v-icon class="WMi-Industry"/>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">
{{ data.created_at }}
</span>
</div>
</v-flex>
<v-flex xs12 sm4 md4>
<div class="WM-d-flex">
<v-icon class="WMi-user"/>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">
{{ data.user ? data.user.name : '' }}
</span>
</div>
</v-flex>
<v-flex xs12 sm12 md12>
<div class="WM-d-flex">
<v-icon class="WMi-pencil"/>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">
{{ data.note }}
</span>
</div>
</v-flex>
</v-layout>
</v-flex>
<v-flex xs12>
<v-layout align-left justify-left wrap class="pt-3">
<h3 class="CSSD-font">Barcode And QRCode Image</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="align-center mt-2">
<v-flex xs12 md6 sm6 v-if="barcodeimg">
<img :src="barcodeimg" class="barcode-container"><br/>
<span class="CSSD-font">Package ID : {{ data.id }}</span>
</v-flex>
<v-flex xs12 md6 sm6 v-if="QRCodeimg" class="WM-Align-R">
<a :href="'https://www.cssd-doc.com/Show/Package/'+data.id+''" target="_blank">
<img :src="QRCodeimg" class="WM-Width-150">
</a>
</v-flex>
</v-layout>
</v-layout>
</v-flex>
<v-flex xs12>
<v-layout align-left justify-left wrap class="pt-3">
<h3 class="CSSD-font mt-0">Items</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="ml-sm-4 WM-Relative">
<template v-if="data.items && data.items.length">
<v-expansion-panel class="WM-Panel">
<v-expansion-panel-content v-for="(item, key) in data.items" :key="key">
<template v-slot:header>
<v-layout row wrap class="CSSD-font">
<span class="item-counter">{{ key + 1 }}</span>
<v-layout row wrap class="pl-2">
<v-flex xs12 sm4 md4>
<span class="sub-text">Item ID:</span> {{ item.id }}
</v-flex>
<v-flex xs12 sm4 md4>
<span class="sub-text">Item Name:</span> {{ item.name }}
</v-flex>
<v-flex xs12 sm4 md4 class="WM-Align-R">
<span v-if="item.pivot">({{ item.pivot.count }})</span>
</v-flex>
</v-layout>
</v-layout>
</template>
<v-card>
<v-card-text>note : {{ item.note }}</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</template>
<template v-else>
<p class="mt-3" style="width: 100%;"> No Item Has Been Selected</p>
</template>
</v-layout>
</v-layout>
</v-flex>
<v-layout row wrap class="ml-4">
<template>
<v-expansion-panel class="WM-Panel">
<v-expansion-panel-content
v-for="(item, key) in data.items" :key="key"
>
<template v-slot:header>
<div>{{ key+1 + ": " + item.name }} ({{ item.pivot.count }})</div>
</template>
<v-card>
<v-card-text>note : {{ item.note }}</v-card-text>
</v-card>
</v-expansion-panel-content>
</v-expansion-panel>
</template>
</v-layout>
</v-layout>
<v-layout row wrap align-center justify-center style="text-align:center">
<v-flex class xs12 md12 sm12 >
<v-flex class xs12 md12 sm12>
<v-btn class="WM-NoShadow WM-Outline-Btn WM-Border WM-Border-Black" @click="addPackage()">
<v-icon class="black--text">keyboard_arrow_left</v-icon>
<span class="black--text">Back</span>
</v-btn>
<v-btn class="WM-CyanBlueGradient-BG" @click="print" style="padding:10px 60px">
<v-btn class="WM-CyanBlueGradient-BG" @click="print" style="padding:10px 60px">
<v-icon class="white--text mr-2 caption">fas fa-print</v-icon>
<span class="white--text">Print</span>
</v-btn>
@@ -91,43 +120,45 @@
</v-btn>
</v-flex>
</v-layout>
</material-card>
</v-container>
</template>
<script>
import axios from "axios";
import { urls } from "@show/config/urls";
import {urls} from "@show/config/urls";
export default {
data: () => ({
data : {},
barcodeimg : '',
QRCodeimg : '',
MedicalCenter : ''
data: {},
barcodeimg: '',
QRCodeimg: '',
MedicalCenter: ''
}),
methods: {
async load(id) {
const result = await axios.get(urls.showPackage(id));
const result = await axios.get(urls.showPackage(id));
if (result.status == 200) {
this.data = result.data.data;
this.generateBarcode(this.data.id);
this.MedicalCenter = this.data.user.medical_center.name;
}
},
if (result.status == 200) {
this.data = result.data.data;
if (this.data) {
this.generateBarcode(this.data.id);
this.MedicalCenter = this.data.user.medical_center.name;
}
}
},
async generateBarcode(packageId) {
const result = await axios.post(urls.Barcode(packageId, 'Package'));
if (result && result.status == 200) {
this.QRCodeimg = result.data.data.QRCode ? result.data.data.QRCode : null;
this.barcodeimg = result.data.data.Barcode ? result.data.data.Barcode : null;
this.QRCodeimg = result.data.data.QRCode ? result.data.data.QRCode : null;
this.barcodeimg = result.data.data.Barcode ? result.data.data.Barcode : null;
}
},
editPackage(packageId){
window.location.href = '/packages/'+packageId+'/edit';
editPackage(packageId) {
window.location.href = '/packages/' + packageId + '/edit';
},
addPackage(){
addPackage() {
window.location.href = '/add-package';
},
print() {
@@ -148,15 +179,7 @@ export default {
"left=0,top=0,width=800,height=900,toolbar=0,scrollbars=0,status=0"
);
WinPrint.document.write(`<!DOCTYPE html>
<html>
<head>
${stylesHtml}
</head>
<body>
${prtHtml}
</body>
</html>`);
WinPrint.document.write(`<!DOCTYPE html><html><head>${stylesHtml} </head> <body>${prtHtml}</body></html>`);
WinPrint.document.close();
WinPrint.focus();
@@ -166,9 +189,30 @@ export default {
},
created() {
if (this.$route.params.package) {
this.load(this.$route.params.package);
}
this.load(this.$route.params.package);
}
},
};
</script>
<style scoped lang="scss">
.barcode-container {
width: 100%;
max-width: 290px;
}
.item-counter {
font-size: 44px;
opacity: .3;
font-family: 'Montserrat-Bold';
line-height: 44px;
position: absolute;
left: 0;
top: 0;
color: #b7b7b7;
}
.sub-text {
font-size: 12px;
}
</style>
@@ -1,141 +1,111 @@
<template>
<v-container grid-list-xs>
<material-card color="black" title="Show Test Result" id="printMe">
<v-layout align-left justify-left wrap class="px-5 my-3">
<h3 class="ml-3 CSSD-font">Test Type : {{ TestType }}</h3>
<v-layout align-left justify-left wrap class="my-3">
<h3 class="ml-4 CSSD-font" style="font-size: 18px!important;">
<span class="WM-Font-16">Test Type :</span>
<span class="font-weight-bold">{{ TestType }}</span>
</h3>
<v-flex xs12>
<hr class="v-divider theme--light" />
<hr class="v-divider theme--light"/>
</v-flex>
<v-layout row wrap class="ml-4">
<v-flex xs12 md12 sm12>
<div class>
<span class="title CSSD-font">{{ data.device_label || 'AutoclaveID' }} :</span>
<span
class="headline ml-2 CSSD-font"
style="letter-spacing:0 !important"
>{{ data.device_id }}</span>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">
{{ data.device_id }}
</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class>
<span class="title CSSD-font">Result :</span>
<span v-if="data.result === 'Reject'" class="NotVerified">
<v-icon class="caption fa fa-times NotVerified"></v-icon>
<v-flex xs12 sm12 class="py-1">
<span class="subtitle-1">Result :</span>
<v-icon size="20"
:class="['caption fa ml-2', data.result == 'Reject'?'NotVerified':( data.result == 'Accept'?'Verified':'')]">
{{ data.result == 'Reject' ? 'fa-times' : (data.result == 'Accept' ? 'fa-check' : '') }}
</v-icon>
<span class="headline ml-1 CSSD-font" style="letter-spacing:0 !important">
{{ data.result }}
</span>
<span v-if="data.result === 'Accept'" class="">
<v-icon class="caption fa fa-check Verified"></v-icon>
</span>
<span
class="headline ml-1 CSSD-font"
style="letter-spacing:0 !important"
>{{ data.result }}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class>
<span class="title CSSD-font">verify :</span>
<span v-if="data.verified === 'NotVerified'" class="NotVerified">
<v-icon class="caption fa fa-times NotVerified"></v-icon>
<v-icon size="20"
:class="['caption fa ml-2', data.verified == 'NotVerified'?'NotVerified':(data.verified == 'Verified'? 'Verified' : '')]">
{{ data.verified == 'NotVerified' ? 'fa-times' :(data.verified == 'Verified' ? 'fa-check':'') }}
</v-icon>
<span class="headline ml-1" style="letter-spacing:0 !important">
{{ data.verified }}
</span>
<span v-if="data.verified === 'Verified'" class="">
<v-icon class="caption fa fa-check Verified"></v-icon>
</span>
<span
class="headline ml-1"
style="letter-spacing:0 !important"
>{{ data.verified }}</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class>
<span class="title CSSD-font">Register User :</span>
<span
class="headline ml-2 CSSD-font"
style="letter-spacing:0 !important"
>{{ User }}</span>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">
{{ User }}
</span>
</div>
</v-flex>
<v-flex xs12 md12 sm12>
<div class>
<span class="title CSSD-font">Date :</span>
<span
class="headline ml-2"
style="letter-spacing:0 !important"
>{{ data.created_at }}</span>
<span class="headline ml-2" style="letter-spacing:0 !important">
{{ data.created_at }}
</span>
</div>
</v-flex>
<v-flex xs12 md6 sm12>
<div class>
<span class="title CSSD-font">Medical Center :</span>
<span
class="headline ml-2 CSSD-font"
style="letter-spacing:0 !important"
>{{ MedicalCenter }}</span>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">
{{ MedicalCenter }}
</span>
</div>
</v-flex>
</v-layout>
</v-layout>
<v-layout align-left justify-left wrap class="px-5 my-3">
<v-layout align-left justify-left wrap class="my-3">
<h3 class="ml-3 CSSD-font">Special Info</h3>
<v-flex xs12>
<hr class="v-divider theme--light" />
<hr class="v-divider theme--light"/>
</v-flex>
<v-layout row wrap class="ml-4">
<template v-if="data.inputs">
<v-flex
xs12
md12
sm12
v-for="(inputData, keyInputs) in data.inputs"
:key="keyInputs"
>
<span class="title">{{keyInputs}} :</span>
<span
class="headline ml-2 CSSD-font"
style="letter-spacing:0 !important"
>{{inputData}}</span>
<v-flex xs12 md12 sm12 v-for="(inputData, keyInputs) in data.inputs" :key="keyInputs">
<span class="title">{{ keyInputs }} :</span>
<span class="headline ml-2 CSSD-font" style="letter-spacing:0 !important">
{{ inputData }}
</span>
</v-flex>
</template>
<template v-if="data.options">
<v-flex
xs12
md12
sm12
v-for="(optionData, keyOptions) in data.options"
:key="keyOptions"
>
<span class="title CSSD-font">{{keyOptions}} :</span>
<span
style="letter-spacing:0 !important"
class="headline ml-2 CSSD-font"
v-for="(data, dataKey) in optionData"
:key="dataKey"
>{{data}},</span>
<v-flex xs12 md12 sm12 v-for="(optionData, keyOptions) in data.options" :key="keyOptions">
<span class="title CSSD-font">{{ keyOptions }} :</span>
<span style="letter-spacing:0 !important" class="headline ml-2 CSSD-font"
v-for="(data, dataKey) in optionData" :key="dataKey">
{{ data }},
</span>
</v-flex>
</template>
<template v-if="data.children">
<v-flex class="mt-4 pb-4" style="border-left:3px solid #32c5d2;border-bottom:1px solid #ddd"
xs12
md12
sm12
v-for="(formData, keyForm) in data.children"
:key="keyForm"
>
<h3 class="ml-3 CSSD-font">{{keyForm}}</h3>
xs12 md12 sm12 v-for="(formData, keyForm) in data.children" :key="keyForm">
<h3 class="ml-3 CSSD-font">{{ keyForm }}</h3>
<div v-for="(childData, keyChild) in formData" :key="keyChild">
<div class="ml-4">
<span class="title CSSD-font">{{keyChild}} :</span>
<span class="title CSSD-font">{{ keyChild }} :</span>
<template v-if="Array.isArray(childData)">
<span
style="letter-spacing:0 !important"
class="headline ml-2 CSSD-font"
v-for="(data, dataKey) in childData"
:key="dataKey"
>{{data}},</span>
<span style="letter-spacing:0 !important" class="headline ml-2 CSSD-font"
v-for="(data, dataKey) in childData" :key="dataKey">
{{ data }},
</span>
</template>
<template v-else>
<span class="headline ml-2 CSSD-font">{{childData}}</span>
<span class="headline ml-2 CSSD-font">{{ childData }}</span>
</template>
</div>
</div>
@@ -143,71 +113,116 @@
</template>
</v-layout>
</v-layout>
<v-layout align-left justify-left wrap class="px-5 my-3">
<h3 class="ml-3 CSSD-font">Image</h3>
<v-flex xs12>
<hr class="v-divider theme--light" />
</v-flex>
<v-layout row wrap class="ml-4">
<v-flex xs6 md2 sm2 v-for="(file, key) in data.files" :key="key">
<template v-if="file.file_type == 'document'">
<a target="_blank" :href="'/'+file.path"><v-icon class="mr-2 caption">fas fa-check</v-icon>{{ file.file_name }}</a>
</template>
<template v-else>
<img :src="'/'+file.path" style="width: 100%" />
</template>
<v-layout align-left justify-left wrap class="my-3">
<v-layout align-left justify-left wrap class="my-3" v-if="data.media && data.media.length">
<h3 class="CSSD-font">Image</h3>
<v-flex xs12>
<hr class="v-divider theme--light"/>
</v-flex>
<v-layout row wrap class="align-center">
<v-flex xs6 md2 sm2 v-for="(file, key) in data.media" :key="key">
<template v-if="file.file_type == 'document'">
<a target="_blank" :href="'/'+file.original_url">
<v-icon class="mr-2 caption">fas fa-check</v-icon>
{{ file.file_name }}
</a>
</template>
<template v-else>
<img :src="file.original_url" style="width: 100%" class="mx-2" @click="openLightbox(key)"/>
</template>
</v-flex>
</v-layout>
</v-layout>
<v-layout align-left justify-left wrap class="my-3">
<h3 class="ml-3 CSSD-font">Barcode And QRCode Image</h3>
<v-flex xs12>
<hr class="v-divider theme--light">
</v-flex>
<v-layout row wrap class="ml-4 align-center mt-2">
<v-flex xs12 md6 sm6 v-if="barcodeimg">
<img :src="barcodeimg" class="barcode-container" style="width: 100%;max-width: 300px;"><br/>
<span class="CSSD-font">Item ID : {{ data.id }}</span>
</v-flex>
<v-flex xs12 md6 sm6 v-if="QRCodeimg" class="WM-Align-C">
<img :src="QRCodeimg" class="WM-Width-150">
</v-flex>
</v-layout>
</v-layout>
</v-layout>
<v-layout row wrap style="text-align:center">
<v-flex class xs12 md2 sm12>
<v-btn
class="WM-NoShadow WM-Outline-Btn WM-Border WM-Border-Gray"
@click="print"
>
<v-btn class="WM-NoShadow WM-Outline-Btn WM-Border WM-Border-Gray" @click="print">
<v-icon class="black--text mr-2 caption">fas fa-print</v-icon>
<span class="black--text">Print</span>
</v-btn>
</v-flex>
</v-layout>
</material-card>
<vue-image-lightbox
v-if="showLightbox"
:media="lightboxImages"
:index="lightboxIndex"
@close="showLightbox = false"
/>
</v-container>
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
import axios from "axios";
import { urls } from "@show/config/urls";
import {urls} from "@show/config/urls";
import VueImageLightbox from 'vue-image-lightbox'
import 'vue-image-lightbox/dist/vue-image-lightbox.min.css'
export default {
data: () => ({
data : {},
TestType : '',
MedicalCenter : '',
User : ''
data: {},
TestType: '',
MedicalCenter: '',
User: '',
QRCodeimg: '',
barcodeimg: '',
showLightbox: false,
lightboxIndex: 0,
lightboxImages: [],
}),
components: {
VueImageLightbox,
},
computed: {
imagesOnly() {
return this.data.media && this.data.media.length ? this.data.media.filter(file => file.mime_type !== 'document') : [];
},
},
methods: {
async load(id) {
const result = await axios.get(urls.showTestResult(id));
const result = await axios.get(urls.showTestResult(id));
if (result.status == 200) {
this.data = result.data.data;
if (result.status == 200) {
this.data = result.data.data;
this.TestType = result.data.data.test_type.name;
this.MedicalCenter = result.data.data.user.medical_center.name;
this.User = this.data.user.name;
}
},
if (this.data) {
this.generateBarcode(this.data);
}
}
},
async generateBarcode(item) {
const result = await axios.post(urls.Barcode(item.id, 'TestResult'));
if (result && result.status == 200) {
this.QRCodeimg = result.data.data.QRCode ? result.data.data.QRCode : null;
this.barcodeimg = result.data.data.Barcode ? result.data.data.Barcode : null;
}
},
print() {
const prtHtml = document.getElementById("printMe").innerHTML;
// Get all stylesheets HTML
let stylesHtml = "";
for (const node of [
...document.querySelectorAll('link[rel="stylesheet"], style')
]) {
stylesHtml += node.outerHTML;
}
for (const node of [...document.querySelectorAll('link[rel="stylesheet"], style')])
{stylesHtml += node.outerHTML;}
// Open the print window
const WinPrint = window.open(
@@ -216,26 +231,28 @@ export default {
"left=0,top=0,width=800,height=900,toolbar=0,scrollbars=0,status=0"
);
WinPrint.document.write(`<!DOCTYPE html>
<html>
<head>
${stylesHtml}
</head>
<body>
${prtHtml}
</body>
</html>`);
WinPrint.document.write(`<!DOCTYPE html><html><head>${stylesHtml} </head><body>${prtHtml} </body></html>`);
WinPrint.document.close();
WinPrint.focus();
WinPrint.print();
WinPrint.close();
},
openLightbox(index) {
this.lightboxIndex = index;
this.showLightbox = false;
this.$nextTick(() => {
this.showLightbox = true;
});
}
},
created() {
if (this.$route.params.id) {
this.load(this.$route.params.id);
}
this.load(this.$route.params.id);
}
this.lightboxImages = this.imagesOnly && this.imagesOnly.length ? this.imagesOnly.map(file => ({
src: file.original_url,
thumb: file.original_url,
})) : [];
},
};
+1
View File
@@ -117,6 +117,7 @@ export default [
view: 'TestResult/Show',
meta: {
public: true,
title:'Show Test Result | CSSD Dashboard'
},
},
{
+7 -9
View File
@@ -23,12 +23,12 @@
></v-autocomplete>
</v-flex>
<v-flex xs12 md3 sm3 class="WM-FlexCenter pl-3">
<v-icon class="fas fa-sort-numeric-up mr-2 WM-Margin-B-8"></v-icon>
<v-text-field class="py-3" v-model="filter.sterilizer_id" label="Sterilizer ID" color="black"></v-text-field>
<v-icon class="fas fa-sort-numeric-up mr-2 WM-Margin-B-8"/>
<v-text-field class="py-3" v-model="filter.sterilizer_id" label="Sterilizer ID" color="black"/>
</v-flex>
<v-flex xs12 md3 sm3 class="WM-FlexCenter pl-3">
<v-icon class="fas fa-sort-numeric-up mr-2 WM-Margin-B-8"></v-icon>
<v-text-field class="py-3" v-model="filter.cycle_number" label="Cycle Number" color="black"></v-text-field>
<v-icon class="fas fa-sort-numeric-up mr-2 WM-Margin-B-8"/>
<v-text-field class="py-3" v-model="filter.cycle_number" label="Cycle Number" color="black"/>
</v-flex>
<v-flex xs12 md2 sm3>
<v-btn class="WM-CyanBlueGradient-BG" style="padding:10px 60px" @click="load()">
@@ -78,8 +78,7 @@
<router-link
class="LinkBtn"
v-if="$hasRole('Admin') || item.user_id == $store.state.user.id"
:to="{name: 'EditLabel', params: {label: item.id}}"
>
:to="{name: 'EditLabel', params: {label: item.id}}">
<v-btn v-bind="attrs" v-on="on" color="orange" class="mr-2">
<v-icon class="white--text mr-1 caption">fas fa-pen</v-icon>
<span>Edit</span>
@@ -95,8 +94,7 @@
color="pink"
class="WM-ActionButton mr-2"
@click="remove(item.id)"
v-if="$hasRole('Admin') || item.user_id == $store.state.user.id"
>
v-if="$hasRole('Admin') || item.user_id == $store.state.user.id">
<v-icon class="white--text mr-2 caption">fas fa-times</v-icon>
<span>Remove</span>
</v-btn>
@@ -119,7 +117,7 @@
</v-layout>
<v-divider></v-divider>
<div class="text-xs-center" v-if="lastPage > 1">
<v-pagination color="black" v-model="currentPage" :length="lastPage" :total-visible="6"></v-pagination>
<v-pagination color="black" v-model="currentPage" :length="lastPage" :total-visible="6"/>
</div>
<v-layout row wrap align-center justify-center class="mt-3">
<router-link to="/dashboard">
+6
View File
@@ -0,0 +1,6 @@
<?php
return [
'reset_password' => "کد فعالسازی شما: :activation_code
لغو ۱۱",
];
+6
View File
@@ -0,0 +1,6 @@
<?php
return [
'reset_password' => "کد فعالسازی شما: :activation_code
لغو ۱۱",
];
+10 -3
View File
@@ -31,11 +31,11 @@ Route::group(['namespace' => 'Api'], function () {
});
Route::middleware('auth:api')->group(function () {
Route::get('TestTypes/ListNames', [TestTypeController::class, 'listNames']);
Route::get('TestTypes/List', [TestTypeController::class, 'list']);
Route::post('/TestTypes/Barcode/{TestType}', [TestTypeController::class, 'generateBarcode']);
Route::resource('TestTypes', TestTypeController::class);
Route::resource('MedicalCenters', MedicalCenterController::class);
Route::post('/GetInputs', [TestTypeController::class, 'getInputs']);
Route::get('/GetInputs/{idOrCode}', [TestTypeController::class, 'getInputs']); // Route::post('/GetInputs', [TestTypeController::class, 'getInputs']) این بود قبلا
Route::get('/GetInfo', [UserController::class, 'getInfo']);
Route::get('Users/MedicalCenter/{MedicalCenter}', [UserController::class, 'getByMedicalCenter']);
@@ -83,15 +83,22 @@ Route::middleware('auth:api')->group(function () {
Route::get('export/items', [ExportController::class, 'items']);
Route::get('export/packages', [ExportController::class, 'packages']);
Route::get('export/cycles', [ExportController::class, 'cycles']);
Route::namespace('Media')->group(function () {
Route::post('store_media', StoreMedia::class);
Route::delete('destroy_media/{media}', DestroyMedia::class);
});
});
Route::get('/show-item/{Item}',[ItemController::class, 'show'])->middleware('guest');
Route::get('/show-item/udi/{udi}',[ItemController::class, 'showUdi'])->middleware('guest');
Route::get('/show-package/{Package}',[PackageController::class, 'show'])->middleware('guest');
Route::post('/BarCode/{Code}/{Type?}', [BarCodeController::class, 'generateBarcode']);
Route::post('Package/Barcode/{Code}', [BarCodeController::class, 'generatePackageBarcode']);
Route::post('Package/QRCode/{Package}', [BarCodeController::class, 'generatePackageQRCode']);
Route::get('TestResults/{id}', [TestResultController::class, 'show']);
Route::get('smstesting',function(){
dd(env('SMS_WEBSERVICE', ''),env('SMS_USERNAME', ''),env('SMS_PASSWORD', ''),env('SMS_FROM_NUMBER', ''));
});
+7
View File
@@ -77,3 +77,10 @@ Route::post('Package/QRCode/{Package}', 'BarCodeController@generatePackageQRCode
Route::any('{all}', function () {
return view('welcome');
})->where(['all' => '.*']);
Route::any('ping', function () {
return response()->json([
'message' => 'pong'
]);
});