init commit
This commit is contained in:
commit
567fd46741
|
|
@ -0,0 +1,94 @@
|
|||
# Created by https://www.gitignore.io
|
||||
|
||||
### OSX ###
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear on external disk
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
|
||||
### Django ###
|
||||
*.log
|
||||
*.pot
|
||||
*.pyc
|
||||
__pycache__/
|
||||
local_settings.py
|
||||
|
||||
.env
|
||||
venv
|
||||
db.sqlite3
|
||||
iralex
|
||||
|
||||
|
||||
storage
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# This file is a template, and might need editing before it works on your project.
|
||||
# This is a sample GitLab CI/CD configuration file that should run without any modifications.
|
||||
# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
|
||||
# it uses echo commands to simulate the pipeline execution.
|
||||
#
|
||||
# A pipeline is composed of independent jobs that run scripts, grouped into stages.
|
||||
# Stages run in sequential order, but jobs within stages run in parallel.
|
||||
#
|
||||
# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
|
||||
#
|
||||
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
|
||||
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
|
||||
#
|
||||
# To contribute improvements to CI/CD templates, please follow the Development guide at:
|
||||
# https://docs.gitlab.com/ee/development/cicd/templates.html
|
||||
# This specific template is located at:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
|
||||
|
||||
stages: # List of stages for jobs, and their order of execution
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
|
||||
build-job: # This job runs in the build stage, which runs first.
|
||||
script: echo 'this should run on pull requests'
|
||||
only:
|
||||
- https://gitlab.com/yo3ef.amini/iralex-backend
|
||||
|
||||
unit-test-job: # This job runs in the test stage.
|
||||
stage: test # It only starts when the job in the build stage completes successfully.
|
||||
script:
|
||||
- echo "Running unit tests... This will take about 60 seconds."
|
||||
- sleep 60
|
||||
- echo "Code coverage is 90%"
|
||||
|
||||
lint-test-job: # This job also runs in the test stage.
|
||||
stage: test # It can run at the same time as unit-test-job (in parallel).
|
||||
script:
|
||||
- echo "Linting code... This will take about 10 seconds."
|
||||
- sleep 10
|
||||
- echo "No lint issues found."
|
||||
|
||||
deploy-job: # This job runs in the deploy stage.
|
||||
stage: deploy # It only runs when *both* jobs in the test stage complete successfully.
|
||||
environment: production
|
||||
script:
|
||||
- echo "Deploying application..."
|
||||
- echo "Application successfully deployed."
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Header add Access-Control-Allow-Origin "*"
|
||||
Header add Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="Django default" uuid="d1ff0dae-7faf-4db7-9477-d34e07ee1dd1">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<imported>true</imported>
|
||||
<remarks>$PROJECT_DIR$/detective_book/settings.py</remarks>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://ira-lex.postgres.database.azure.com:5432/iralex</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<Languages>
|
||||
<language minSize="107" name="Python" />
|
||||
</Languages>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="32">
|
||||
<item index="0" class="java.lang.String" itemvalue="httpx" />
|
||||
<item index="1" class="java.lang.String" itemvalue="motor" />
|
||||
<item index="2" class="java.lang.String" itemvalue="PyJWT" />
|
||||
<item index="3" class="java.lang.String" itemvalue="cffi" />
|
||||
<item index="4" class="java.lang.String" itemvalue="h11" />
|
||||
<item index="5" class="java.lang.String" itemvalue="pycparser" />
|
||||
<item index="6" class="java.lang.String" itemvalue="requests" />
|
||||
<item index="7" class="java.lang.String" itemvalue="rfc3986" />
|
||||
<item index="8" class="java.lang.String" itemvalue="sniffio" />
|
||||
<item index="9" class="java.lang.String" itemvalue="starlette" />
|
||||
<item index="10" class="java.lang.String" itemvalue="certifi" />
|
||||
<item index="11" class="java.lang.String" itemvalue="anyio" />
|
||||
<item index="12" class="java.lang.String" itemvalue="urllib3" />
|
||||
<item index="13" class="java.lang.String" itemvalue="uvicorn" />
|
||||
<item index="14" class="java.lang.String" itemvalue="passlib" />
|
||||
<item index="15" class="java.lang.String" itemvalue="pydantic" />
|
||||
<item index="16" class="java.lang.String" itemvalue="pymongo" />
|
||||
<item index="17" class="java.lang.String" itemvalue="six" />
|
||||
<item index="18" class="java.lang.String" itemvalue="asgiref" />
|
||||
<item index="19" class="java.lang.String" itemvalue="python-multipart" />
|
||||
<item index="20" class="java.lang.String" itemvalue="click" />
|
||||
<item index="21" class="java.lang.String" itemvalue="bcrypt" />
|
||||
<item index="22" class="java.lang.String" itemvalue="fastapi" />
|
||||
<item index="23" class="java.lang.String" itemvalue="colorama" />
|
||||
<item index="24" class="java.lang.String" itemvalue="typing_extensions" />
|
||||
<item index="25" class="java.lang.String" itemvalue="charset-normalizer" />
|
||||
<item index="26" class="java.lang.String" itemvalue="python-decouple" />
|
||||
<item index="27" class="java.lang.String" itemvalue="pytz" />
|
||||
<item index="28" class="java.lang.String" itemvalue="httpcore" />
|
||||
<item index="29" class="java.lang.String" itemvalue="idna" />
|
||||
<item index="30" class="java.lang.String" itemvalue="weasyprint" />
|
||||
<item index="31" class="java.lang.String" itemvalue="pydyf" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="N802" />
|
||||
<option value="N812" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredIdentifiers">
|
||||
<list>
|
||||
<option value="pymongo.results.UpdateResult.__await__" />
|
||||
<option value="bool.*" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="django" name="Django">
|
||||
<configuration>
|
||||
<option name="rootFolder" value="$MODULE_DIR$" />
|
||||
<option name="settingsModule" value="detective_book/settings.py" />
|
||||
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
|
||||
<option name="environment" value="<map/>" />
|
||||
<option name="doNotUseTestRunner" value="false" />
|
||||
<option name="trackFilePattern" value="migrations" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Django Lib" level="project" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
<option name="format" value="PLAIN" />
|
||||
<option name="myDocStringFormat" value="Plain" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<component name="libraryTable">
|
||||
<library name="Django Lib">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/venv/Lib/site-packages" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (iralex-backend)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/iralex-backend.iml" filepath="$PROJECT_DIR$/.idea/iralex-backend.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PySciProjectComponent">
|
||||
<option name="PY_SCI_VIEW_SUGGESTED" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"editor.tabSize": 4,
|
||||
"editor.useTabStops": true,
|
||||
"editor.insertSpaces": true,
|
||||
"cSpell.enabledLanguageIds": [
|
||||
"COBOL",
|
||||
"ACUCOBOL"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"notifications": {
|
||||
"is_new_calender_in_email": false,
|
||||
"is_new_calender_in_app": false,
|
||||
"is_new_calender_in_mobile": false,
|
||||
"is_update_calender_in_app": false,
|
||||
"is_update_calender_in_mobile": false,
|
||||
"is_delete_calender_in_app": true,
|
||||
"is_delete_calender_in_mobile": true,
|
||||
"is_document_in_email": true,
|
||||
"is_document_in_app": true,
|
||||
"is_document_in_mobile": true,
|
||||
"is_matter_Subscribed_in_app": true,
|
||||
"is_matter_Subscribed_in_mobile": true,
|
||||
"is_matter_status_in_app": true,
|
||||
"is_matter_status_in_mobile": true,
|
||||
"is_delete_matter_in_app": true,
|
||||
"is_delete_matter_in_mobile": true,
|
||||
"is_update_matter_in_email": true,
|
||||
"is_update_matter_in_app": true,
|
||||
"is_update_matter_in_mobile": true,
|
||||
"is_note_subscribed_in_app": true,
|
||||
"is_note_subscribed_in_mobile": true,
|
||||
"is_update_note_in_app": true,
|
||||
"is_update_note_in_mobile": true,
|
||||
"is_delete_note_in_app": true,
|
||||
"is_deleted_note_in_mobile": true,
|
||||
"is_phone_log_subscribed_in_app": true,
|
||||
"is_phone_log_subscribed_in_mobile": true,
|
||||
"is_update_phone_log_in_app": true,
|
||||
"is_update_phone_log_in_mobile": true,
|
||||
"is_delete_phone_log_in_app": true,
|
||||
"is_delete_phone_log_in_mobile": true,
|
||||
"is_secure_message_in_email": true,
|
||||
"is_task_in_email": true,
|
||||
"is_task_in_app": true,
|
||||
"is_task_in_mobile": true,
|
||||
"is_update_task_in_email": true,
|
||||
"is_update_task_in_app": true,
|
||||
"is_update_task_in_mobile": true,
|
||||
"is_deleted_task_in_email": true,
|
||||
"is_deleted_task_in_app": true,
|
||||
"is_mobile_task_in_mobile": true,
|
||||
"is_complete_task_in_email": true,
|
||||
"is_complete_task_in_app": true,
|
||||
"is_complete_task_in_mobile": true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEA4xwH1WNhrDVfW7AavFcUeaVg7nGOyZqympKBn+mR1LbtD4Sc
|
||||
lOxZHP7zRiBsIzsqotz8qcU64opnoZjvvK9VdysQYOeGnrj6X/mc2y5iPPH/RSce
|
||||
gU9ErF2abG7WJ9podCnhATtr9Fh7H2jEp8XW7z+muHaD6uy+SQ3cIACuSWQU+rnR
|
||||
+0N2mHOZqSCeQubGkuY+awsNOwTG9WiRRPkZqxbUbfT5ZB18WsHRkXsAnKhoPYiU
|
||||
aH60R2M4mHNeeTqofbkuv7fXYpAeSHzzFEP+mas9BDEoOCA0oP4/xLMPcGA3HwIP
|
||||
ew4NbK4pPScmiULWOJsqNZeXIgfz5zhmWwEpeQIDAQABAoIBAEnmHBJuVSDg+Rdv
|
||||
lTOFrk7q5kCQSOMG6GjtlSpAqUgrAbZT81NuGI0b1HMUJ7vLC9OUzs47NC701EW7
|
||||
6v5dmxS8uYaer6pEDIxgP47+Z87m+6Y31XBEJ9diWdZAtoSfR+/MlL9+42DNzbpp
|
||||
r9vbv1V4Q7qwLbqqsDw7O05ailusjRfBN4x0wP7X63Pzb6SAfafA7QcGKC27Og5o
|
||||
2H2XyWHj5a//DWac1eTn+T7HB+8/f7BhxIy9at6xC8xBM1A9gTulaWg64hP6Rxi2
|
||||
BziPwWMogwUSIGhmM4uUI01cdIr89wJn6OAn0odp/3LWZnW+J0w5P2PvbEBtnTUF
|
||||
lftKh+UCgYEA/i9hrqf5ZOitVivtQOuCt5AYjxGcRjt+Pf11nidExkz0937/LPMn
|
||||
sG32+VDzAcfOfAGKvbpAk2q8nGV6q1gOFR/71UEzu+Ff92m6pKyue2okCFKx6HwK
|
||||
N+yqGQ6l6tw0KfEksOIoidAhKauZsOWxkVQDOiuEPIBY7v/djCo1vjcCgYEA5Lso
|
||||
gwGzqz5RtN/5/8P70e2bszcoOS0UFbpXlg/6zjQczVczMqQlMm+lIt08tJplLY2k
|
||||
WC5ef2jXtBW3ULveZTr3YS53HVrjjIzNLu7pxiMIUGrMuLMcby8LYVYHW5dJheTU
|
||||
RD8FY+2l6/Ry8xklYepu6QbDuYS3zIi5cv/w/c8CgYBCQKNbXNj6XlNf1I9AjqJB
|
||||
qkNcdyCehb8/9SKFGIMqlMB9ChME6lP7/o2TKnBMlIHTfKtnDHbsdbO3qBOzOX5i
|
||||
LzX6vcX4QKQ83sgRSBkqfd3qdXN9v2cCcKNdaJ4Ce2b1T69ak3gxg5hBPkMPAq+n
|
||||
y5gTv2f2RRXpJbPfZtkfPQKBgAh/l7K+ZnGPYDPLOpuxKXMUU/ulqf3t2dgw0z5F
|
||||
G7l7oDJU8hcImEU2drlD5RSExAucPqX0Gxi6yYDsaaI7SLkUJsrakhxqGxhGxvze
|
||||
bZsqBA4Q2chnB0BuTAryylUx2s55wRVEDiw3UTniHD9CCOyJbFOGJ9GFx9p2ngVS
|
||||
0x5rAoGAacqYwilbjiiWAtie1g5ZMmgiTAjysIdCAKyz3HLMKjDptAAUFPM8Vwh+
|
||||
YLy6Ekq/+HfUHhC5TDfNWwJa4XGs76bhUva4zgpbUJV+5pkHNn024akyxk+BtVBa
|
||||
k7cpeFap0Oo/bvsmC0gA4r3mqug1MuwjUPAfzCOSA+euqBz7EVc=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
setting.py is in detective_book folder you can see the settings of this project
|
||||
|
||||
# ira-lex Project Readme
|
||||
|
||||
Welcome to the documentation for the **ira-lex** Django project! This document serves as a guide to understanding the project's structure, functionality, and how to get it up and running on your local machine.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Project Overview](#project-overview)
|
||||
- [Features](#features)
|
||||
- [Getting Started](#getting-started)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation](#installation)
|
||||
- [Configuration](#configuration)
|
||||
- [Usage](#usage)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
## Project Overview
|
||||
|
||||
[Project Name] is a Django-based web application designed to [briefly describe the project's main purpose and features].
|
||||
|
||||
## Features
|
||||
|
||||
- admin panel and customer panel (this repo contains just customer repo)
|
||||
|
||||
## Getting Started
|
||||
|
||||
Follow these instructions to set up and run the project on your local machine.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Python [version 3.10]
|
||||
- [Database] (MongoDB, PostgreSQL, Redis)[you don't need setup database in you local system. the database is run from server]
|
||||
- [python celery and another library in requirements.txt file]
|
||||
|
||||
### Installation
|
||||
|
||||
1. Clone this repository to your local machine:
|
||||
|
||||
```bash
|
||||
git clone [git@gitlab.com:yo3ef.amini/iralex-backend.git]
|
||||
cd [iralex-backend]
|
||||
```
|
||||
|
||||
2. Create a virtual environment:
|
||||
|
||||
```bash
|
||||
virtualenv venv -p python3.10
|
||||
```
|
||||
|
||||
3. Activate the virtual environment:
|
||||
|
||||
- On Windows:
|
||||
|
||||
```bash
|
||||
venv\Scripts\activate
|
||||
```
|
||||
|
||||
- On macOS and Linux:
|
||||
|
||||
```bash
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
4. Install the required dependencies:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Copy the `.env.example` file to `.env`:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
2. Edit the `.env` file and set the necessary environment variables:
|
||||
|
||||
- `SECRET_KEY`: Django secret key for security
|
||||
- `DEBUG`: Set to `True` for development, `False` for production
|
||||
- `DATABASE_URL`: URL to your database
|
||||
- [Other configuration variables]
|
||||
|
||||
## Usage
|
||||
|
||||
1. Apply database migrations:
|
||||
|
||||
```bash
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
2. Create a superuser account:
|
||||
|
||||
```bash
|
||||
python manage.py createsuperuser
|
||||
```
|
||||
|
||||
3. Start the development server:
|
||||
|
||||
```bash
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
4. Access the application in your web browser at `http://127.0.0.1:8000/`.
|
||||
|
||||
|
||||
Thank you for your interest in the [ira-lex] project. If you have any questions or need further assistance, please don't hesitate to [https://gitlab.com/ehsangheychisaz]. Happy coding!
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
from django.core.handlers.wsgi import WSGIRequest
|
||||
|
||||
from account.TokenI import TokenI
|
||||
from core.utility.Response import Response
|
||||
|
||||
|
||||
class Authentication:
|
||||
@staticmethod
|
||||
def Authenticate():
|
||||
def MethodWrapper(ViewMethod):
|
||||
def ArgumentsWrapper(*args, **kwargs):
|
||||
request = None
|
||||
for arg in args:
|
||||
if isinstance(arg, WSGIRequest):
|
||||
request = arg
|
||||
try:
|
||||
if hasattr(request, 'lawyerUser'):
|
||||
return ViewMethod(*args, **kwargs)
|
||||
elif request.method == "OPTIONS":
|
||||
return Response("Unauthorized")
|
||||
else:
|
||||
return Response("Unauthorized").Unauthorized()
|
||||
except TokenI.TokenNotFoundException:
|
||||
return Response("Unauthorized").Unauthorized()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
raise e
|
||||
|
||||
return ArgumentsWrapper
|
||||
|
||||
return MethodWrapper
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
from hashlib import sha256
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
|
||||
from account.models import LawyerUser
|
||||
from django.db.models import Q
|
||||
|
||||
from core.file_manager.models import FileInfo
|
||||
from core.utility.Response import Response
|
||||
|
||||
|
||||
class LawyerUserI:
|
||||
lawyerUser: LawyerUser = None
|
||||
|
||||
def __init__(self, request: WSGIRequest = None, canCreate=False, canUpdate=False, *args, **kwargs):
|
||||
|
||||
if hasattr(request, "lawyerUser"):
|
||||
print(request.lawyerUser)
|
||||
self.lawyerUser = request.lawyerUser
|
||||
|
||||
for arg in args:
|
||||
if isinstance(arg, LawyerUser):
|
||||
self.lawyerUser = arg
|
||||
|
||||
_id = kwargs["id"] if "id" in kwargs else None
|
||||
email_address = kwargs["email_address"] if "email_address" in kwargs else request.Input(
|
||||
"email_address") if request is not None else None
|
||||
first_name = kwargs["first_name"] if "first_name" in kwargs else request.Input(
|
||||
"first_name") if request is not None else None
|
||||
last_name = kwargs["last_name"] if "last_name" in kwargs else request.Input(
|
||||
"last_name") if request is not None else None
|
||||
phone_number = kwargs["phone_number"] if "phone_number" in kwargs else request.Input(
|
||||
"phone_number") if request is not None else None
|
||||
is_main = kwargs["is_main"] if "is_main" in kwargs else None
|
||||
main = kwargs["main"] if "main" in kwargs else None
|
||||
if not None and not isinstance(main, LawyerUser):
|
||||
main = LawyerUser.objects.filter(pk=main).first()
|
||||
# password = sha256(kwargs["password"].encode("utf-8")).hexdigest() if "password" in kwargs else None
|
||||
avatar_id = kwargs["avatar_id"] if "avatar_id" in kwargs else request.Input(
|
||||
"avatar_id") if request is not None else None
|
||||
role_id = kwargs["role_id"] if "role_id" in kwargs else request.Input("role_id") if request is not None else None
|
||||
|
||||
fillParams = {
|
||||
"email_address": email_address,
|
||||
"password": None,
|
||||
"first_name": first_name,
|
||||
"last_name": last_name,
|
||||
"phone_number": phone_number,
|
||||
"is_main": is_main,
|
||||
"main": main,
|
||||
"avatar_id": avatar_id,
|
||||
"role_id":role_id
|
||||
}
|
||||
|
||||
if self.lawyerUser is None:
|
||||
if _id is None:
|
||||
self.lawyerUser = LawyerUser.objects.filter(Q(email_address=email_address)).first()
|
||||
elif email_address is None:
|
||||
self.lawyerUser = LawyerUser.objects.filter(Q(pk=_id)).first()
|
||||
else:
|
||||
self.lawyerUser = LawyerUser.objects.filter(Q(pk=_id) and Q(email_address=email_address)).first()
|
||||
|
||||
isCreated = False
|
||||
if canCreate and (request is None or request.method == "POST"):
|
||||
if self.lawyerUser is None and first_name is not None and last_name is not None and email_address is not None:
|
||||
self.lawyerUser = LawyerUser.objects.create(**fillParams)
|
||||
isCreated = True
|
||||
|
||||
try:
|
||||
if canUpdate and not isCreated and (request is None or request.method == "PUT"):
|
||||
if self.lawyerUser is not None and self.lawyerUser.password is not None:
|
||||
for k in fillParams.keys():
|
||||
if fillParams[k] is not None or k == 'avatar_id':
|
||||
self.lawyerUser.__setattr__(k, fillParams[k])
|
||||
self.lawyerUser.save()
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
if canUpdate and request is None or (request is not None and request.method == "POST" and isCreated) or (
|
||||
request is not None and request.method == "PATH" and not isCreated):
|
||||
if fillParams["avatar_id"] is not None:
|
||||
fileInfo = FileInfo.objects.get(pk=fillParams["avatar_id"])
|
||||
if fileInfo is not None:
|
||||
if fileInfo.maintainer.id == self.lawyerUser.id:
|
||||
fileInfo.section = FileInfo.Section.AVATAR
|
||||
fileInfo.save()
|
||||
|
||||
self.lawyerUser.save()
|
||||
|
||||
@staticmethod
|
||||
def LoadFromRequest(request):
|
||||
lawyerUserI = LawyerUserI()
|
||||
lawyerUserI.lawyerUser = request.lawyerUser
|
||||
lawyerUserI.request = request
|
||||
|
||||
@staticmethod
|
||||
def LoadById(_id):
|
||||
try:
|
||||
lawyerUserI = LawyerUserI()
|
||||
lawyerUserI.lawyerUser = LawyerUser.objects.get(pk=_id)
|
||||
return lawyerUserI
|
||||
except ObjectDoesNotExist:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def LoadByIdIfUserCanFindThat(_lawyerUser, _id):
|
||||
|
||||
lawyerUserI = None
|
||||
findWantLawyerUserI = LawyerUserI.LoadById(_id)
|
||||
|
||||
if isinstance(_lawyerUser, LawyerUser):
|
||||
lawyerUserI = LawyerUserI.LoadById(_lawyerUser.id)
|
||||
elif isinstance(_lawyerUser, LawyerUserI):
|
||||
lawyerUserI = _lawyerUser
|
||||
elif isinstance(_lawyerUser, int):
|
||||
lawyerUserI = LawyerUserI.LoadById(_lawyerUser)
|
||||
|
||||
if lawyerUserI.lawyerUser.GetMain().id == findWantLawyerUserI.lawyerUser.GetMain().id:
|
||||
return findWantLawyerUserI
|
||||
|
||||
raise LawyerUserI.NotAllowedException
|
||||
|
||||
def SetPassword(self, password):
|
||||
self.lawyerUser.password = sha256(password.encode("utf-8")).hexdigest()
|
||||
self.lawyerUser.save()
|
||||
return self
|
||||
|
||||
def AddUser(self, email_address, first_name, last_name, phone_number, inviter_name='', role_id=''):
|
||||
from core.verifier.VerifierI import VerifierI
|
||||
from core.verifier.models import PendingVerify
|
||||
|
||||
if LawyerUser.objects.filter(email_address=email_address).first() is not None:
|
||||
raise LawyerUserI.ConflictException
|
||||
|
||||
verifier = VerifierI(emailAddress=email_address)
|
||||
verifier.CreatePending(PendingVerify.VerifyType.REGISTER, payload={
|
||||
"email_address": email_address,
|
||||
"first_name": first_name,
|
||||
"last_name": last_name,
|
||||
"phone_number": phone_number,
|
||||
"is_main": False,
|
||||
"role_id": role_id,
|
||||
"main": self.lawyerUser.GetMain().id
|
||||
}).SendMail(inviter_name=inviter_name, invited_name=first_name + ' ' + last_name, invited_user=True)
|
||||
|
||||
class ConflictException(Exception):
|
||||
pass
|
||||
|
||||
class NotAllowedException(Exception):
|
||||
pass
|
||||
|
||||
def chek_contract_validate(self):
|
||||
pass
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import random
|
||||
import string
|
||||
from hashlib import sha256
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.utils import timezone
|
||||
|
||||
from .LawyerUserI import LawyerUserI
|
||||
from .models import Token
|
||||
|
||||
|
||||
class TokenI:
|
||||
class TokenSection:
|
||||
AUTHENTICATION = "lua" # LawyerUser Authentication
|
||||
|
||||
token: Token = None
|
||||
|
||||
def __init__(self, section: str, _id: int = None, _token: str = None, emailAddress: str = None,
|
||||
password: str = None):
|
||||
if _id is not None:
|
||||
try:
|
||||
self.token = Token.objects.get(pk=_id)
|
||||
except ObjectDoesNotExist:
|
||||
raise TokenI.TokenNotFoundException
|
||||
|
||||
elif _token is not None:
|
||||
try:
|
||||
self.token = Token.objects.get(token=_token)
|
||||
except ObjectDoesNotExist:
|
||||
raise TokenI.TokenNotFoundException
|
||||
elif emailAddress is not None:
|
||||
lawyerUser = LawyerUserI(email_address=emailAddress)
|
||||
if lawyerUser.lawyerUser is None:
|
||||
raise TokenI.UserNotFoundException
|
||||
else:
|
||||
if lawyerUser.lawyerUser.is_removed == True:
|
||||
raise TokenI.UserDeactivate
|
||||
if lawyerUser.lawyerUser is not None and lawyerUser.lawyerUser.password == sha256(
|
||||
password.encode("utf-8")).hexdigest():
|
||||
_token = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(64))
|
||||
_token = section + " " + _token
|
||||
self.token = Token.objects.create(lawyer_user=lawyerUser.lawyerUser,
|
||||
token=_token,
|
||||
expire_date=timezone.now() + timezone.timedelta(days=30))
|
||||
else:
|
||||
raise TokenI.UserPassWrongException
|
||||
|
||||
def SetLawyerUser(self, lawyerUser):
|
||||
self.token.lawyer_user = lawyerUser
|
||||
self.token.save()
|
||||
return self
|
||||
|
||||
class UserNotFoundException(Exception):
|
||||
pass
|
||||
class UserPassWrongException(Exception):
|
||||
pass
|
||||
|
||||
class UserDeactivate(Exception):
|
||||
pass
|
||||
|
||||
class TokenNotFoundException(Exception):
|
||||
pass
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import *
|
||||
from core.utility.DatabaseU import DatabaseU
|
||||
|
||||
DatabaseU.RegisterModelToAdmin(LawyerUser)
|
||||
DatabaseU.RegisterModelToAdmin(Token)
|
||||
DatabaseU.RegisterModelToAdmin(Group)
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AccountConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'account'
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
# Generated by Django 4.0.2 on 2022-02-26 16:07
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='LawyerUser',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('email_address', models.CharField(max_length=64, unique=True)),
|
||||
('password', models.CharField(blank=True, max_length=64, null=True)),
|
||||
('avatar_url', models.CharField(blank=True, max_length=128, null=True)),
|
||||
('first_name', models.CharField(max_length=64)),
|
||||
('last_name', models.CharField(max_length=64)),
|
||||
('phone_number', models.CharField(blank=True, max_length=64, null=True)),
|
||||
('is_main', models.BooleanField(default=True)),
|
||||
('total_uploaded_size', models.PositiveBigIntegerField(default=0)),
|
||||
('is_verified', models.BooleanField(default=False)),
|
||||
('is_removed', models.BooleanField(default=False)),
|
||||
('permission', models.CharField(blank=True, choices=[('application_super_admin', 'Application Super Admin'), ('super_admin', 'Super Admin Permission'), ('admin', 'Admin Permission'), ('accounting', 'Accounting Permission'), ('user_a', 'User A Permission'), ('user_b', 'User B Permission')], default='super_admin', max_length=64, null=True)),
|
||||
('is_application_admin', models.BooleanField(default=False)),
|
||||
('main', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='account.lawyeruser')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Token',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('token', models.CharField(max_length=128)),
|
||||
('expire_date', models.DateField()),
|
||||
('payload', models.CharField(blank=True, max_length=256, null=True)),
|
||||
('lawyer_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='account.lawyeruser')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Group',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('title', models.CharField(max_length=64)),
|
||||
('main', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='group_main_user', to='account.lawyeruser')),
|
||||
('users', models.ManyToManyField(to='account.LawyerUser')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FirebaseToken',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('web_client_token', models.CharField(blank=True, max_length=256, null=True)),
|
||||
('phone_client_token', models.CharField(blank=True, max_length=256, null=True)),
|
||||
('lawyer_user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='account.lawyeruser')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.0.2 on 2022-05-16 15:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='lawyeruser',
|
||||
name='firm_avatar_url',
|
||||
field=models.CharField(blank=True, max_length=256, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='lawyeruser',
|
||||
name='avatar_url',
|
||||
field=models.CharField(blank=True, max_length=256, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.2.3 on 2022-09-01 10:33
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0002_lawyeruser_firm_avatar_url_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='firebasetoken',
|
||||
old_name='phone_client_token',
|
||||
new_name='android_client_token',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='firebasetoken',
|
||||
name='ios_client_token',
|
||||
field=models.CharField(blank=True, max_length=256, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 3.2.3 on 2022-09-03 23:14
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0004_auto_20220901_1033'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='firebasetoken',
|
||||
name='lawyer_user',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='fcm_token', to='account.lawyeruser'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.2.3 on 2022-09-06 21:44
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('file_manager', '0001_initial'),
|
||||
('account', '0005_alter_firebasetoken_lawyer_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='lawyeruser',
|
||||
name='avatar_url',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='lawyeruser',
|
||||
name='avatar',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='file_manager.fileinfo'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# Generated by Django 3.2.3 on 2022-09-15 18:56
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0006_auto_20220906_2144'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Role',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=128)),
|
||||
('count', models.IntegerField(default=0)),
|
||||
('key', models.CharField(max_length=128)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Admin',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('first_name', models.CharField(max_length=128)),
|
||||
('last_name', models.CharField(max_length=128)),
|
||||
('full_name', models.CharField(blank=True, max_length=256, null=True)),
|
||||
('email', models.CharField(max_length=64)),
|
||||
('gender', models.SmallIntegerField(choices=[(1, 'male'), (2, 'female'), (3, 'unknown')])),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('phone', models.CharField(blank=True, max_length=32, null=True)),
|
||||
('address', models.CharField(blank=True, max_length=512, null=True)),
|
||||
('password', models.CharField(max_length=512)),
|
||||
('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='account.role')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.2.3 on 2022-09-15 21:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0007_admin_role'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='admin',
|
||||
name='email',
|
||||
field=models.CharField(max_length=64, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='admin',
|
||||
name='gender',
|
||||
field=models.SmallIntegerField(choices=[(1, 'male'), (2, 'female'), (3, 'unknown')], default=3),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 3.2.3 on 2022-12-17 20:24
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0008_auto_20220915_2121'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='lawyeruser',
|
||||
name='permission',
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 3.2.3 on 2022-12-17 21:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('permission', '0002_delete_userrole'),
|
||||
('account', '0009_remove_lawyeruser_permission'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='lawyeruser',
|
||||
name='permissions',
|
||||
field=models.ManyToManyField(to='permission.Role'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.3 on 2022-12-18 22:54
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0010_lawyeruser_permissions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='lawyeruser',
|
||||
old_name='permissions',
|
||||
new_name='roles',
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.2.3 on 2023-01-05 18:21
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('permission', '0006_rolepermission_type'),
|
||||
('account', '0011_rename_permissions_lawyeruser_roles'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='lawyeruser',
|
||||
name='roles',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='lawyeruser',
|
||||
name='role',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='users', to='permission.role'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.2.3 on 2023-06-16 21:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('permission', '0009_auto_20230616_2115'),
|
||||
('account', '0012_auto_20230105_1821'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='lawyeruser',
|
||||
name='permissions',
|
||||
field=models.ManyToManyField(related_name='user_permissions', to='permission.Permission'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='lawyeruser',
|
||||
name='permissions_deny',
|
||||
field=models.ManyToManyField(related_name='user_permissions_deny', to='permission.Permission'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.2.2 on 2024-02-22 13:10
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0013_auto_20230616_2115'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SearchHistory',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('search', models.TextField(null=True)),
|
||||
('create_time', models.DateTimeField(auto_now=True)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='account.lawyeruser')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
import string
|
||||
|
||||
import random
|
||||
from django.utils import timezone
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import Q, Sum
|
||||
from django.forms import model_to_dict
|
||||
|
||||
|
||||
class LawyerUser(models.Model):
|
||||
SEARCH = [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email_address"
|
||||
]
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
email_address = models.CharField(max_length=64, unique=True)
|
||||
password = models.CharField(max_length=64, blank=True, null=True)
|
||||
avatar = models.ForeignKey(
|
||||
'file_manager.FileInfo', null=True, blank=True, on_delete=models.SET_NULL)
|
||||
firm_avatar_url = models.CharField(max_length=256, blank=True, null=True)
|
||||
first_name = models.CharField(max_length=64)
|
||||
last_name = models.CharField(max_length=64)
|
||||
phone_number = models.CharField(max_length=64, blank=True, null=True)
|
||||
is_main = models.BooleanField(default=True)
|
||||
main = models.ForeignKey(
|
||||
"self", blank=True, null=True, on_delete=models.CASCADE)
|
||||
role = models.ForeignKey('permission.Role', on_delete=models.SET_NULL,
|
||||
null=True, blank=True, related_name='users')
|
||||
permissions = models.ManyToManyField(
|
||||
'permission.Permission', related_name="user_permissions")
|
||||
|
||||
permissions_deny = models.ManyToManyField(
|
||||
'permission.Permission', related_name="user_permissions_deny")
|
||||
# جمع مقدار آپلود شده (به بایت)
|
||||
total_uploaded_size = models.PositiveBigIntegerField(default=0)
|
||||
is_verified = models.BooleanField(default=False)
|
||||
is_removed = models.BooleanField(default=False)
|
||||
# آخرین فاکتور
|
||||
|
||||
# آیا ادمین سیستم است ؟
|
||||
is_application_admin = models.BooleanField(default=False)
|
||||
|
||||
def GetMain(self):
|
||||
return self if self.is_main else self.main
|
||||
|
||||
@staticmethod
|
||||
def Update(request, _id):
|
||||
data = request.bodyDict
|
||||
user = LawyerUser.GetReadableUsers(request.lawyerUser).get(pk=_id)
|
||||
for key in data.keys():
|
||||
setattr(user, key, data[key])
|
||||
user.save()
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def Delete(request, _id):
|
||||
try:
|
||||
user = LawyerUser.GetReadableUsers(request.lawyerUser).get(pk=_id)
|
||||
user.is_removed = True
|
||||
user.save()
|
||||
return True
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
|
||||
def TotalFirmUploadedSize(self):
|
||||
return LawyerUser.objects.filter(Q(id=self.GetMain().id) |
|
||||
Q(main__id=self.GetMain().id)).aggregate(Sum("total_uploaded_size"))[
|
||||
"total_uploaded_size__sum"]
|
||||
|
||||
@staticmethod
|
||||
def UpdateOrCreate(**kwargs):
|
||||
lawyerUser, isCreated = LawyerUser.objects.update_or_create(email_address=kwargs["email_address"],
|
||||
defaults=kwargs)
|
||||
return lawyerUser
|
||||
|
||||
@staticmethod
|
||||
def GetReadableUsers(lawyerUser):
|
||||
return LawyerUser.objects.filter(Q(main__id=lawyerUser.GetMain().id) | Q(pk=lawyerUser.GetMain().id))
|
||||
|
||||
def ToDict(self, showPhoneNumber=False, showMainLawyerUserPhoneNumber=False, showSubscription=True):
|
||||
|
||||
try:
|
||||
subscription = self.subscription
|
||||
except Exception:
|
||||
subscription = None
|
||||
|
||||
return {
|
||||
"id": self.id,
|
||||
"created_at": self.created_at,
|
||||
"updated_at": self.updated_at,
|
||||
"email_address": self.email_address,
|
||||
"first_name": self.first_name,
|
||||
"last_name": self.last_name,
|
||||
"is_main": self.is_main,
|
||||
# "phone_number": self.phone_number if showPhoneNumber else "hidden",
|
||||
"phone_number": self.phone_number,
|
||||
"roles": {'id': self.role.id, 'title': self.role.title} if self.role else {},
|
||||
"avatar_url": self.avatar.GetUrl() if self.avatar else '',
|
||||
"firm_avatar_url": self.GetMain().firm_avatar_url,
|
||||
"main": self.main.ToDict(showPhoneNumber=showMainLawyerUserPhoneNumber) if self.main is not None else None,
|
||||
"subscription": subscription.ToDict() if showSubscription and subscription is not None else None if subscription is None else "hidden",
|
||||
"total_uploaded_size": self.total_uploaded_size,
|
||||
"total_firm_uploaded_size": self.TotalFirmUploadedSize(),
|
||||
}
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
|
||||
class NotOwnException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Token(models.Model):
|
||||
class Section:
|
||||
AUTHENTICATION = "lua" # LawyerUser Authentication
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
token = models.CharField(max_length=128)
|
||||
lawyer_user = models.ForeignKey(
|
||||
LawyerUser, on_delete=models.CASCADE, blank=True, null=True)
|
||||
expire_date = models.DateField()
|
||||
payload = models.CharField(max_length=256, blank=True, null=True)
|
||||
|
||||
def ToDict(self):
|
||||
_dict = model_to_dict(self)
|
||||
_dict["lawyer_user"] = self.lawyer_user.ToDict(showPhoneNumber=True)
|
||||
return _dict
|
||||
|
||||
@staticmethod
|
||||
def CreateAuthenticationToken(lawyerUser):
|
||||
_token = ''.join(random.choice(string.ascii_letters +
|
||||
string.digits) for _ in range(64))
|
||||
_token = Token.Section.AUTHENTICATION + " " + _token
|
||||
token = Token.objects.create(lawyer_user=lawyerUser, token=_token,
|
||||
expire_date=timezone.now() + timezone.timedelta(days=30))
|
||||
return token
|
||||
|
||||
|
||||
class Group(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
title = models.CharField(max_length=64)
|
||||
main = models.ForeignKey(
|
||||
LawyerUser, related_name="group_main_user", on_delete=models.CASCADE)
|
||||
users = models.ManyToManyField(LawyerUser)
|
||||
|
||||
def ToDict(self):
|
||||
modelDict = model_to_dict(self)
|
||||
_users = []
|
||||
usersAll = self.users.all()
|
||||
for u in usersAll:
|
||||
_users.append(u.ToDict())
|
||||
|
||||
modelDict["users"] = _users
|
||||
|
||||
return modelDict
|
||||
|
||||
|
||||
class FirebaseToken(models.Model):
|
||||
lawyer_user = models.OneToOneField(
|
||||
LawyerUser, on_delete=models.CASCADE, related_name='fcm_token')
|
||||
web_client_token = models.CharField(max_length=256, null=True, blank=True)
|
||||
ios_client_token = models.CharField(max_length=256, null=True, blank=True)
|
||||
android_client_token = models.CharField(
|
||||
max_length=256, null=True, blank=True)
|
||||
|
||||
@staticmethod
|
||||
def GetValidatedDataFromRequest(request):
|
||||
# noinspection PyDictCreation
|
||||
data = {}
|
||||
data = request.bodyDict
|
||||
data["lawyer_user"] = request.lawyerUser
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def Create(request):
|
||||
data = FirebaseToken.GetValidatedDataFromRequest(request)
|
||||
firebaseToken = FirebaseToken.objects.create(**data)
|
||||
return firebaseToken
|
||||
|
||||
@staticmethod
|
||||
def Update(request, _id):
|
||||
firebaseAccount = FirebaseToken.objects.get(pk=_id)
|
||||
|
||||
data = FirebaseToken.GetValidatedDataFromRequest(request)
|
||||
|
||||
for key in data.keys():
|
||||
setattr(firebaseAccount, key, data[key])
|
||||
|
||||
firebaseAccount.save()
|
||||
|
||||
return firebaseAccount
|
||||
|
||||
def ToDict(self):
|
||||
modelDict = model_to_dict(self)
|
||||
return modelDict
|
||||
|
||||
|
||||
class Role(models.Model):
|
||||
title = models.CharField(max_length=128)
|
||||
count = models.IntegerField(default=0)
|
||||
key = models.CharField(max_length=128)
|
||||
|
||||
|
||||
class Admin(models.Model):
|
||||
first_name = models.CharField(max_length=128)
|
||||
last_name = models.CharField(max_length=128)
|
||||
full_name = models.CharField(max_length=256, null=True, blank=True)
|
||||
email = models.CharField(max_length=64, unique=True)
|
||||
role = models.ForeignKey(
|
||||
Role, null=True, blank=True, on_delete=models.CASCADE)
|
||||
gender = models.SmallIntegerField(choices=[
|
||||
(1, 'male'),
|
||||
(2, 'female'),
|
||||
(3, 'unknown'),
|
||||
], default=3)
|
||||
is_active = models.BooleanField(default=True)
|
||||
phone = models.CharField(max_length=32, null=True, blank=True)
|
||||
address = models.CharField(max_length=512, null=True, blank=True)
|
||||
password = models.CharField(max_length=512)
|
||||
|
||||
|
||||
from django.utils import timezone
|
||||
# Create your models here.
|
||||
class SearchHistory(models.Model):
|
||||
search = models.TextField(null=True)
|
||||
create_time = models.DateTimeField(auto_now=True)
|
||||
user = models.ForeignKey(LawyerUser , on_delete=models.PROTECT)
|
||||
|
||||
def Meta(self):
|
||||
ordering = ['-create_time']
|
||||
def save(self, *args, **kwargs):
|
||||
# Check if the user already has ten or more text entries
|
||||
if SearchHistory.objects.filter(user=self.user).count() >= 10:
|
||||
removeSearch = SearchHistory.objects.filter(user=self.user).first()
|
||||
removeSearch.delete()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.first_name} {self.user.last_name} - {self.search}"
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import json
|
||||
|
||||
from django.urls import path
|
||||
|
||||
from permission.views import getAllPermission, getUserPermission
|
||||
from subscription.subscription import Subscription
|
||||
from messenger.Messenger import Messenger
|
||||
from .views import *
|
||||
|
||||
|
||||
def test(request):
|
||||
Subscription.get_active_contract(request.lawyerUser)
|
||||
return True
|
||||
with open("ex.txt", "a") as res:
|
||||
if request.method == 'POST':
|
||||
var = request.POST
|
||||
if request.method == 'GET':
|
||||
var = request.GET
|
||||
res.write("\n")
|
||||
res.write("test")
|
||||
res.write(json.dumps(var))
|
||||
# Messenger.SendMail(toEmails=['yo3ef.amini@gmail.com'], message="one conected", subject='test')
|
||||
return Response(200)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path("", Account),
|
||||
path("register/", Register),
|
||||
path("forgot/", ForgotPassword),
|
||||
path("change-password/", ChangePassword),
|
||||
path("change-email/", ChangeEmailAddress),
|
||||
path("verify/", Verify),
|
||||
path("token/", GenerateToken),
|
||||
path("add/", AddUser),
|
||||
path("edit/<int:_id>", EditFirmUser),
|
||||
path("delete/<int:_id>", DeleteFirmUser),
|
||||
path("permit/<int:userId>/", PermitPermission),
|
||||
path("list/", GetListOfFirmUser),
|
||||
path("edit/", GetListOfFirmUser),
|
||||
path("group/", GroupView),
|
||||
path("group/<int:groupId>/", SetGroupUsers),
|
||||
path("group/<int:groupId>/edit/", SetGroupUsers),
|
||||
path("group/<int:groupId>/delete/", DeleteGroup),
|
||||
path("firebase/token/", AssignLawyerUserFirebaseToken),
|
||||
path("google/login/", LoginWithGoogle),
|
||||
path("facebook/login/" , LoginWithFacebook),
|
||||
path("google/oauth2/", GoogleOAuth2),
|
||||
path("firm/avatar/", FirmAvatar),
|
||||
path("payment/", test),
|
||||
path("permissions", getAllPermission),
|
||||
path("my-permission", getUserPermission),
|
||||
]
|
||||
|
|
@ -0,0 +1,433 @@
|
|||
import os
|
||||
from hashlib import sha256
|
||||
|
||||
from PIL import Image
|
||||
from django.utils import timezone
|
||||
from django.db.models import Q
|
||||
from google.auth.transport import requests
|
||||
from google.oauth2 import id_token
|
||||
from messenger.Messenger import Messenger
|
||||
from account.Authentication import Authentication
|
||||
from account.LawyerUserI import LawyerUserI
|
||||
from account.TokenI import TokenI
|
||||
from account.models import LawyerUser, Group, FirebaseToken, Token
|
||||
from contact.models import Contact
|
||||
from core.file_manager.models import FileInfo
|
||||
from core.utility.Response import Response
|
||||
from core.verifier.VerifierI import VerifierI
|
||||
from core.verifier.models import PendingVerify
|
||||
from detective_book.settings import ROOT_DIR
|
||||
from core.utility.Response import Response
|
||||
from subscription.models import Contract
|
||||
from subscription.subscription import Subscription
|
||||
from django.http import JsonResponse
|
||||
from django.http import Http404 , HttpResponse
|
||||
from datetime import datetime, time, timedelta
|
||||
import pytz
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def Account(request):
|
||||
# if request.method == "GET" :
|
||||
return Response(LawyerUserI(id=request.lawyerUser.id, request=request, canUpdate=True).lawyerUser.ToDict(True))
|
||||
# else:
|
||||
# return Response.NotAllowed()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def Register(request):
|
||||
# if request.method == "POST":
|
||||
email = request.Input("email_address")
|
||||
print(email)
|
||||
if email == None or email == "":
|
||||
return Response({"status": False}).NotAcceptable()
|
||||
if LawyerUser.objects.filter(email_address=email.lower()).exists() != True:
|
||||
verifier = VerifierI(emailAddress=request.Input("email_address"))
|
||||
verifier.CreatePending(PendingVerify.VerifyType.REGISTER, payload={
|
||||
"email_address": request.Input("email_address"),
|
||||
"first_name": request.Input("first_name"),
|
||||
"last_name": request.Input("last_name"),
|
||||
"phone_number": request.Input("phone_number"),
|
||||
"is_main": True,
|
||||
# "permission": LawyerUser.Permission.SUPER_ADMIN_PERMISSION
|
||||
})
|
||||
verifier.SendMail(name=request.Input("first_name", "") + " " + request.Input("last_name", ""))
|
||||
# verifier.SendNewmail(name=request.Input("first_name", "") + " " + request.Input("last_name", ""),
|
||||
# phone=request.Input("phone_number"))
|
||||
return Response({"status": True})
|
||||
else:
|
||||
return Response({"status": False, "message": "Email address is exists"}).Conflict()
|
||||
|
||||
|
||||
|
||||
|
||||
def ForgotPassword(request):
|
||||
if request.method == "POST":
|
||||
if len(request.Input("email_address")) == 0:
|
||||
return Response("bad request").NotAllowed()
|
||||
lawyerUser = LawyerUser.objects.filter(
|
||||
email_address=request.Input("email_address")).first()
|
||||
if lawyerUser is None:
|
||||
return Response("User not found").NotFound()
|
||||
userLastForget = PendingVerify.objects.filter(email_address=request.Input("email_address")).order_by("-created_at").first()
|
||||
if userLastForget:
|
||||
lasttime = userLastForget.created_at
|
||||
time = datetime.now()
|
||||
print((time - lasttime).seconds)
|
||||
if (time-lasttime).seconds > 180 :
|
||||
verifier = VerifierI(emailAddress=request.Input("email_address")).CreatePending(
|
||||
PendingVerify.VerifyType.FORGOT_PASSWORD, payload=None)
|
||||
verifier.SendMail(name=f'{lawyerUser.first_name} {lawyerUser.last_name}')
|
||||
return Response({"status": True})
|
||||
else:
|
||||
return Response(f"you are in time limit for {180 - (time-lasttime).seconds}").NotAllowed()
|
||||
else:
|
||||
verifier = VerifierI(emailAddress=request.Input("email_address")).CreatePending(
|
||||
PendingVerify.VerifyType.FORGOT_PASSWORD, payload=None)
|
||||
verifier.SendMail(name=f'{lawyerUser.first_name} {lawyerUser.last_name}')
|
||||
|
||||
return Response({"status": True})
|
||||
if request.method == "OPTIONS":
|
||||
return Response("not allowed").NotAllowed()
|
||||
|
||||
# if request.method == "POST":
|
||||
# if request.Input("email_address")== "":
|
||||
# return Response("email field is empty").NotFound()
|
||||
# else:
|
||||
# lawyerUser = LawyerUser.objects.filter(
|
||||
# email_address=request.Input("email_address")).first()
|
||||
# if lawyerUser is None:
|
||||
# return Response("User not found").NotFound()
|
||||
# verifier = VerifierI(emailAddress=request.Input("email_address"))
|
||||
# timeClient = PendingVerify.objects.filter(email_address=request.Input("email_address")).first().created_at
|
||||
# timeRequest = datetime.now()
|
||||
# if (timeRequest - timeClient).seconds >= 180:
|
||||
# verifier.CreatePending(
|
||||
# PendingVerify.VerifyType.FORGOT_PASSWORD, payload=None)
|
||||
# verifier.SendMail()
|
||||
# return Response({"status": True}).Correct()
|
||||
# else :
|
||||
# return Response(f"you are in time limit and you should wait for {180 - (timeRequest - timeClient).seconds} seconds").NotAcceptable()
|
||||
# else:
|
||||
# Response.NotAllowed()
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def AddUser(request):
|
||||
try:
|
||||
if not Subscription.chek_user_limit(request.lawyerUser):
|
||||
return JsonResponse(data={
|
||||
"message": "You have reached the limit of adding users. "
|
||||
}, status=422)
|
||||
|
||||
LawyerUserI(request).AddUser(email_address=request.Input("email_address"),
|
||||
first_name=request.Input("first_name"),
|
||||
last_name=request.Input("last_name"),
|
||||
phone_number=request.Input(
|
||||
"phone_number"),
|
||||
role_id=request.Input("role_id"),
|
||||
# permission=LawyerUser.Permission.USER_B_PERMISSION, TODO Add Permission
|
||||
inviter_name=request.lawyerUser.first_name + ' ' + request.lawyerUser.last_name)
|
||||
|
||||
return Response({"status": True})
|
||||
except LawyerUserI.ConflictException:
|
||||
return Response("Email address exists.").Conflict()
|
||||
|
||||
|
||||
def Verify(request):
|
||||
try:
|
||||
lawyerUser = None
|
||||
verifier = VerifierI(code=request.Input("code"))
|
||||
payload = verifier.pendingVerify.payload
|
||||
if verifier.pendingVerify.verify_type == PendingVerify.VerifyType.REGISTER:
|
||||
if 'main' in payload:
|
||||
main = LawyerUser.objects.get(pk=payload['main'])
|
||||
main_contract = Subscription.get_active_contract(main)
|
||||
if not main_contract:
|
||||
raise "You`re inviter plan has been expired."
|
||||
can_add_user = Subscription.chek_user_limit(main)
|
||||
if not can_add_user:
|
||||
raise "You`re inviter can`t add any user more."
|
||||
main_contract.user_usage += 1
|
||||
main_contract.save()
|
||||
lawyerUser = LawyerUserI(**payload, canCreate=True)
|
||||
lawyerUser.lawyerUser.contracts.add(main_contract)
|
||||
lawyerUser.SetPassword(request.Input("password"))
|
||||
|
||||
else:
|
||||
lawyerUser = LawyerUserI(**payload, canCreate=True)
|
||||
_now = timezone.now()
|
||||
new_trial = Contract.objects.create(
|
||||
status=2,
|
||||
from_date=_now,
|
||||
to_date=_now + timezone.timedelta(days=14),
|
||||
owner_id=lawyerUser.lawyerUser.id,
|
||||
user_limit=9999,
|
||||
allowed_delay_days=0,
|
||||
discounted_price=0,
|
||||
total_price=0,
|
||||
payed_amount=0,
|
||||
installments_count=1,
|
||||
payable_amount=0,
|
||||
storage_limit=1000000,
|
||||
type=3,
|
||||
)
|
||||
new_trial.save()
|
||||
lawyerUser.lawyerUser.contracts.add(new_trial)
|
||||
lawyerUser.SetPassword(request.Input("password"))
|
||||
print(lawyerUser.lawyerUser.first_name ,lawyerUser.lawyerUser.last_name,lawyerUser.lawyerUser.phone_number)
|
||||
verifier.SendNewmail(name=lawyerUser.lawyerUser.first_name+lawyerUser.lawyerUser.last_name,
|
||||
phone=lawyerUser.lawyerUser.phone_number)
|
||||
elif verifier.pendingVerify.verify_type == PendingVerify.VerifyType.FORGOT_PASSWORD:
|
||||
lawyerUser = LawyerUserI.LoadById(
|
||||
LawyerUser.objects.get(email_address=verifier.pendingVerify.email_address).id)
|
||||
lawyerUser.SetPassword(request.Input("password"))
|
||||
elif verifier.pendingVerify.verify_type == PendingVerify.VerifyType.CHANGE_EMAIL_ADDRESS:
|
||||
lawyerUser = LawyerUserI.LoadById(
|
||||
LawyerUser.objects.get(email_address=verifier.pendingVerify.payload["old_email_address"]).id)
|
||||
lawyerUser.lawyerUser.email_address = verifier.pendingVerify.payload["email_address"]
|
||||
lawyerUser.lawyerUser.save()
|
||||
|
||||
verifier.DeleteSimilar()
|
||||
|
||||
return Response(lawyerUser.lawyerUser)
|
||||
except VerifierI.CodeNotFoundException:
|
||||
return Response({"message": "Code not found"}).NotFound()
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def ChangePassword(request):
|
||||
if request.lawyerUser.password == sha256(request.bodyDict["old_password"].encode("utf-8")).hexdigest():
|
||||
request.lawyerUser.password = sha256(
|
||||
request.bodyDict["new_password"].encode("utf-8")).hexdigest()
|
||||
request.lawyerUser.save()
|
||||
return Response(request.lawyerUser)
|
||||
else:
|
||||
return Response({"message": "Old password is incorrect"}).NotAcceptable()
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def ChangeEmailAddress(request):
|
||||
verifier = VerifierI(emailAddress=request.Input("email_address"))
|
||||
verifier.CreatePending(PendingVerify.VerifyType.CHANGE_EMAIL_ADDRESS, payload={
|
||||
"old_email_address": request.lawyerUser.email_address,
|
||||
"email_address": request.Input("email_address")
|
||||
})
|
||||
verifier.SendMail(request.lawyerUser.first_name +
|
||||
" " + request.lawyerUser.last_name)
|
||||
return Response({"status": True})
|
||||
|
||||
|
||||
def GenerateToken(request):
|
||||
try:
|
||||
token = TokenI(section=TokenI.TokenSection.AUTHENTICATION, emailAddress=request.Input("email_address"),
|
||||
password=request.Input("password"))
|
||||
return Response(token.token)
|
||||
except TokenI.UserNotFoundException:
|
||||
return Response({"message": "Cannot find the user with this email"}).NotFound()
|
||||
except TokenI.UserPassWrongException:
|
||||
return Response({"message": "Cannot find the user with this pass"}).NotFound()
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def PermitPermission(request, userId):
|
||||
if request.method == "PUT":
|
||||
try:
|
||||
lawyerUserI = LawyerUserI.LoadByIdIfUserCanFindThat(
|
||||
request.lawyerUser, userId)
|
||||
lawyerUserI.lawyerUser.permission = request.Input("permission")
|
||||
lawyerUserI.lawyerUser.save()
|
||||
|
||||
return Response(content=lawyerUserI.lawyerUser)
|
||||
|
||||
except LawyerUserI.NotAllowedException:
|
||||
return Response("Not found-ER8529422344").NotFound()
|
||||
else:
|
||||
return Response("Nothing").NotAllowed()
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def GetListOfFirmUser(request):
|
||||
return Response(
|
||||
LawyerUser.objects.filter(Q(pk=request.lawyerUser.GetMain().id) | Q(main_id=request.lawyerUser.GetMain().id), is_removed=False).order_by('-created_at'))
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def EditFirmUser(request, _id):
|
||||
return Response(LawyerUser.Update(request=request, _id=_id))
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def DeleteFirmUser(request, _id):
|
||||
return Response(LawyerUser.Delete(request, _id=_id))
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
# @Permission.Require(LawyerUser.Permission.ACCOUNTING_PERMISSION)
|
||||
def GroupView(request):
|
||||
if request.method == "GET":
|
||||
list_of_group = Group.objects.filter(main_id=request.lawyerUser.GetMain().id).all().order_by('-created_at')
|
||||
# print(list_of_group)
|
||||
return Response(list_of_group)
|
||||
|
||||
elif request.method == "POST":
|
||||
group = Group.objects.create(title=request.Input(
|
||||
"title"), main=request.lawyerUser.GetMain())
|
||||
if request.Input("users"):
|
||||
for u in request.Input("users"):
|
||||
lawyerUser = LawyerUserI.LoadByIdIfUserCanFindThat(
|
||||
request.lawyerUser.id, u)
|
||||
group.users.add(lawyerUser.lawyerUser)
|
||||
return Response(group)
|
||||
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def SetGroupUsers(request, groupId):
|
||||
if request.method == "GET":
|
||||
group = Group.objects.get(
|
||||
main_id=request.lawyerUser.GetMain().id, pk=groupId)
|
||||
return Response(group)
|
||||
if request.method == "PUT":
|
||||
group = Group.objects.get(
|
||||
main_id=request.lawyerUser.GetMain().id, pk=groupId)
|
||||
group.title = request.Input("title")
|
||||
group.save()
|
||||
group.users.clear()
|
||||
print(request.Input("users"))
|
||||
for u in request.Input("users"):
|
||||
lawyerUser = LawyerUserI.LoadByIdIfUserCanFindThat(
|
||||
request.lawyerUser.id, u)
|
||||
group.users.add(lawyerUser.lawyerUser)
|
||||
|
||||
return Response(group)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def DeleteGroup(request, groupId):
|
||||
group = Group.objects.get(
|
||||
main_id=request.lawyerUser.GetMain().id, pk=groupId)
|
||||
group.delete()
|
||||
return Response({"status": "true"})
|
||||
|
||||
|
||||
# def LoginWithGoogle(request):
|
||||
# clientId = "222474890494-jo5uf8i4tnuggnicdo475fdfk46an9oq.apps.googleusercontent.com"
|
||||
# clientSecret = "psmJdLCoIhqveLqV-scCSb8C"
|
||||
# redirectUri = "https://ira-lex.com/login-by-google/"
|
||||
#
|
||||
# authorizationBaseUrl = "https://accounts.google.com/o/oauth2/v2/auth"
|
||||
# tokenUrl = "https://www.googleapis.com/oauth2/v4/toke"
|
||||
#
|
||||
# scope = ["https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/userinfo.profile"]
|
||||
#
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def AssignLawyerUserFirebaseToken(request):
|
||||
token = FirebaseToken.objects.filter(
|
||||
lawyer_user__id=request.lawyerUser.id).first()
|
||||
|
||||
if token is None:
|
||||
token = FirebaseToken.Create(request)
|
||||
else:
|
||||
token.Update(request, token.id)
|
||||
|
||||
return Response(token)
|
||||
|
||||
|
||||
def LoginWithGoogle(request):
|
||||
loginPageHtmlPath = os.path.join(
|
||||
ROOT_DIR, "assets/google-oauth2/index.html")
|
||||
|
||||
with open(loginPageHtmlPath, "r") as file:
|
||||
loginPageHtml = file.read()
|
||||
|
||||
return Response(loginPageHtml)
|
||||
|
||||
def LoginWithFacebook(request):
|
||||
loginPageHtmlPath = os.path.join(
|
||||
ROOT_DIR, "assets/facebook-login/index.html")
|
||||
|
||||
with open(loginPageHtmlPath, "r") as file:
|
||||
loginPageHtml = file.read()
|
||||
|
||||
return Response(loginPageHtml)
|
||||
def GoogleOAuth2(request):
|
||||
WEB_CLIENT_ID = "986858475219-461v2efu5b1ghfsofnajak56pt806spa.apps.googleusercontent.com"
|
||||
ANDROID_CLIENT_ID = "986858475219-51t72fthf2p6p79rjgg47e6se5oalvf7.apps.googleusercontent.com"
|
||||
|
||||
try:
|
||||
idInfo = id_token.verify_oauth2_token(
|
||||
request.bodyDict["id_token"], requests.Request())
|
||||
|
||||
if idInfo["aud"] not in [WEB_CLIENT_ID, ANDROID_CLIENT_ID,
|
||||
"986858475219-1n02hgjcbuc5e9onjb2hv558rie9mnlo.apps.googleusercontent.com",
|
||||
"986858475219-1n02hgjcbuc5e9onjb2hv558rie9mnlo.apps.googleusercontent.com"]:
|
||||
raise ValueError("Could not verify audience")
|
||||
|
||||
lawyerUserParams = {
|
||||
"email_address": idInfo["email"],
|
||||
"first_name": idInfo["given_name"],
|
||||
"last_name": idInfo["family_name"],
|
||||
"avatar_url": idInfo["picture"],
|
||||
"is_verified": True
|
||||
}
|
||||
|
||||
lawyerUser = LawyerUser.UpdateOrCreate(**lawyerUserParams)
|
||||
|
||||
return Response(Token.CreateAuthenticationToken(lawyerUser))
|
||||
|
||||
except Exception as e:
|
||||
return Response(str(e)).Forbidden()
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def FirmAvatar(request):
|
||||
oldFileInfo = None
|
||||
|
||||
if request.lawyerUser.GetMain().firm_avatar_url is not None:
|
||||
oldFileInfo = FileInfo.GetByFileName(
|
||||
request.lawyerUser.GetMain().firm_avatar_url.split("/")[-1], True)
|
||||
|
||||
if "file" in request.FILES:
|
||||
try:
|
||||
fileInfo = FileInfo.CreateByRequest(request, True, 3 * 1024 * 1024)
|
||||
except FileInfo.TooLargeException:
|
||||
return Response().TooLarge()
|
||||
|
||||
try:
|
||||
Image.open(fileInfo.path).verify()
|
||||
except Exception:
|
||||
os.remove(fileInfo.path)
|
||||
fileInfo.delete()
|
||||
return Response().Forbidden()
|
||||
|
||||
request.lawyerUser.GetMain().firm_avatar_url = fileInfo.GetUrl()
|
||||
request.lawyerUser.GetMain().save()
|
||||
|
||||
else:
|
||||
request.lawyerUser.GetMain().firm_avatar_url = None
|
||||
request.lawyerUser.GetMain().save()
|
||||
|
||||
if oldFileInfo is not None:
|
||||
try:
|
||||
if os.path.exists(oldFileInfo.path):
|
||||
os.remove(oldFileInfo.path)
|
||||
oldFileInfo.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return Response(request.lawyerUser.GetMain())
|
||||
|
||||
|
||||
def get_fullname(user, contact=False):
|
||||
if not contact and isinstance(user, LawyerUser):
|
||||
if not user:
|
||||
return ''
|
||||
return user.first_name + ' ' + user.last_name
|
||||
elif isinstance(user, Contact):
|
||||
person = user.person_set.first()
|
||||
company = user.company_set.first()
|
||||
return (person.first_name + ' ' + person.last_name) if person else company.name
|
||||
return '-'
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ActivityConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'activity'
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
# Generated by Django 4.0.2 on 2022-02-26 16:07
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('account', '0001_initial'),
|
||||
('contact', '0001_initial'),
|
||||
('matter', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ExpenseCategory',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=32)),
|
||||
('rate', models.FloatField(default=0)),
|
||||
('expense_type', models.IntegerField(choices=[(1, 'Disbursement'), (2, 'Recoveries')])),
|
||||
('is_removed', models.BooleanField(default=False)),
|
||||
('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='account.lawyeruser')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TimeEntryCategory',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=32)),
|
||||
('rate', models.FloatField(default=0)),
|
||||
('is_removed', models.BooleanField(default=False)),
|
||||
('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='account.lawyeruser')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TimeEntry',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('duration', models.FloatField(default=0)),
|
||||
('date', models.DateField(blank=True, null=True)),
|
||||
('rate', models.FloatField(default=0)),
|
||||
('description', models.TextField(default='')),
|
||||
('is_no_billable', models.BooleanField(default=False)),
|
||||
('is_removed', models.BooleanField(default=False)),
|
||||
('is_used_in_invoice', models.BooleanField(default=False)),
|
||||
('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='activity.timeentrycategory')),
|
||||
('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='time_entry_creator_set', to='account.lawyeruser')),
|
||||
('matter', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='matter.matter')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='time_entry_user_set', to='account.lawyeruser')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ExpenseEntry',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('date', models.DateField(blank=True, null=True)),
|
||||
('is_used_in_invoice', models.BooleanField(default=False)),
|
||||
('expense_type', models.IntegerField(choices=[(1, 'Disbursement'), (2, 'Recoveries')])),
|
||||
('reference', models.CharField(blank=True, max_length=32, null=True)),
|
||||
('quantity', models.IntegerField(default=1)),
|
||||
('amount', models.FloatField(default=0)),
|
||||
('rate', models.FloatField(default=0)),
|
||||
('description', models.TextField(blank=True, null=True)),
|
||||
('is_removed', models.BooleanField(default=False)),
|
||||
('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='activity.expensecategory')),
|
||||
('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='expense_entry_creator_set', to='account.lawyeruser')),
|
||||
('matter', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='matter.matter')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='expense_entry_user_set', to='account.lawyeruser')),
|
||||
('vendor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contact.contact')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 3.2.3 on 2022-12-07 20:12
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('task', '0002_alter_tasklist_practice_area'),
|
||||
('activity', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='timeentry',
|
||||
name='task',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='task.task'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.2.2 on 2025-01-02 08:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('activity', '0002_timeentry_task'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='expenseentry',
|
||||
name='is_tax',
|
||||
field=models.BooleanField(default=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='timeentry',
|
||||
name='is_tax',
|
||||
field=models.BooleanField(default=False, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
import os
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from celery import shared_task
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.forms import model_to_dict
|
||||
from django.utils.dateparse import parse_date
|
||||
|
||||
from account.models import LawyerUser
|
||||
# from account.views import get_fullname
|
||||
from contact.models import Contact
|
||||
from detective_book.settings import ROOT_DIR, BASE_URL
|
||||
from matter.models import Matter
|
||||
from messenger.Messenger import Messenger
|
||||
from permission.check_permission import CheckUserNotification
|
||||
from task.models import Task
|
||||
from timeline.timeline import Timeline
|
||||
|
||||
|
||||
# دسته بندی TimeEntry
|
||||
class TimeEntryCategory(models.Model):
|
||||
SEARCH = ["name"]
|
||||
creator = models.ForeignKey(LawyerUser, on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=32)
|
||||
# نرخ پیشفرض این دسته
|
||||
rate = models.FloatField(default=0)
|
||||
is_removed = models.BooleanField(default=False)
|
||||
|
||||
def ToDict(self):
|
||||
modelDict = model_to_dict(self)
|
||||
modelDict["creator"] = self.creator.ToDict()
|
||||
return modelDict
|
||||
|
||||
@staticmethod
|
||||
def GetValidatedDataFromRequest(request):
|
||||
data = request.bodyDict
|
||||
data["creator"] = request.lawyerUser
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def Create(request):
|
||||
data = ExpenseCategory.GetValidatedDataFromRequest(request)
|
||||
timeEntryCategory = TimeEntryCategory.objects.create(**data)
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=timeEntryCategory,
|
||||
action=Timeline.Action.CREATE,
|
||||
message=None)
|
||||
|
||||
return timeEntryCategory
|
||||
|
||||
@staticmethod
|
||||
def Update(request, _id):
|
||||
data = TimeEntryCategory.GetValidatedDataFromRequest(request)
|
||||
timeEntryCategory = TimeEntryCategory.List(request).get(pk=_id)
|
||||
for key in data.keys():
|
||||
setattr(timeEntryCategory, key, data[key])
|
||||
timeEntryCategory.save()
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=timeEntryCategory,
|
||||
action=Timeline.Action.EDIT,
|
||||
message=None)
|
||||
return timeEntryCategory
|
||||
|
||||
@staticmethod
|
||||
def Remove(request, _id):
|
||||
timeEntryCategory = TimeEntryCategory.List(request).get(pk=_id)
|
||||
timeEntryCategory.is_removed = True
|
||||
timeEntryCategory.save()
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=timeEntryCategory,
|
||||
action=Timeline.Action.REMOVE,
|
||||
message=None)
|
||||
return timeEntryCategory
|
||||
|
||||
@staticmethod
|
||||
def List(request, inIsRemoved=False):
|
||||
return TimeEntryCategory.objects.filter(Q(creator__id=request.lawyerUser.GetMain().id) |
|
||||
Q(creator__main__id=request.lawyerUser.GetMain().id)).filter(
|
||||
is_removed=inIsRemoved).all()
|
||||
|
||||
|
||||
class TimeEntry(models.Model):
|
||||
SEARCH = [
|
||||
"description",
|
||||
"matter__title",
|
||||
"user__first_name",
|
||||
"user__last_name",
|
||||
]
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
creator = models.ForeignKey(LawyerUser, on_delete=models.CASCADE, related_name="time_entry_creator_set")
|
||||
# پرونده
|
||||
matter = models.ForeignKey(Matter, blank=True, null=True, on_delete=models.CASCADE)
|
||||
# مدت زمان به دقیقه
|
||||
duration = models.FloatField(default=0)
|
||||
|
||||
date = models.DateField(blank=True, null=True)
|
||||
user = models.ForeignKey(LawyerUser, on_delete=models.CASCADE, related_name="time_entry_user_set")
|
||||
rate = models.FloatField(default=0)
|
||||
|
||||
category = models.ForeignKey(TimeEntryCategory, blank=True, null=True, on_delete=models.CASCADE)
|
||||
description = models.TextField(default="")
|
||||
task = models.ForeignKey(Task, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
# آیا در فاکتور میرود ؟
|
||||
is_no_billable = models.BooleanField(default=False)
|
||||
is_removed = models.BooleanField(default=False)
|
||||
# اگر در فاکتور استفاده شده باشد True میشود. چون هم TimeEntry باید یک بار فاکتور شود
|
||||
is_used_in_invoice = models.BooleanField(default=False)
|
||||
is_tax = models.BooleanField(default=False , null=True)
|
||||
discount_cash = models.BigIntegerField(null=True)
|
||||
discount = models.IntegerField(null=True)
|
||||
@staticmethod
|
||||
def GetValidatedDataFromRequest(request):
|
||||
data = request.bodyDict
|
||||
|
||||
data["creator"] = request.lawyerUser
|
||||
|
||||
if "matter" in data and data["matter"] is not None:
|
||||
data["matter"] = Matter.GetReadableMatters(lawyerUser=request.lawyerUser).get(pk=data["matter"])
|
||||
|
||||
if "user" in data and data["user"] is not None:
|
||||
data["user"] = LawyerUser.GetReadableUsers(request.lawyerUser).get(pk=data["user"])
|
||||
if "category" in data and data["category"] is not None:
|
||||
data["category"] = TimeEntryCategory.objects.get(pk=data["category"])
|
||||
|
||||
if "date" in data and data["date"] is not None:
|
||||
data["date"] = parse_date(request.Input("date"))
|
||||
|
||||
return data
|
||||
|
||||
def ToDict(self):
|
||||
modelDict = model_to_dict(self)
|
||||
modelDict["creator"] = self.creator.ToDict()
|
||||
if self.matter is not None:
|
||||
modelDict["matter"] = self.matter.ToDict()
|
||||
if self.user is not None:
|
||||
modelDict["user"] = self.user.ToDict()
|
||||
if self.category is not None:
|
||||
modelDict["category"] = self.category.ToDict()
|
||||
|
||||
return modelDict
|
||||
|
||||
@staticmethod
|
||||
def Create(request):
|
||||
data = TimeEntry.GetValidatedDataFromRequest(request)
|
||||
timeEntry = TimeEntry.objects.create(**data)
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=timeEntry,
|
||||
action=Timeline.Action.CREATE,
|
||||
message=None)
|
||||
if 'matter' in data and data['matter']:
|
||||
matter = data['matter']
|
||||
matter.usage_budget += int(float(timeEntry.rate) * float(timeEntry.duration))
|
||||
matter.save()
|
||||
if matter.has_notify and matter.usage_budget >= matter.budget * (matter.notify_limit / 100):
|
||||
sendBudgetLimitWarning.delay(matter_id=matter.id)
|
||||
return timeEntry
|
||||
|
||||
@staticmethod
|
||||
def Update(request, _id):
|
||||
data = TimeEntry.GetValidatedDataFromRequest(request)
|
||||
timeEntry = TimeEntry.List(request).get(pk=_id)
|
||||
if 'matter' in data and data['matter']:
|
||||
matter = data['matter']
|
||||
matter.usage_budget -= int(float(timeEntry.rate) * float(timeEntry.duration))
|
||||
matter.save()
|
||||
for key in data.keys():
|
||||
setattr(timeEntry, key, data[key])
|
||||
timeEntry.save()
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=timeEntry,
|
||||
action=Timeline.Action.EDIT,
|
||||
message=None)
|
||||
if 'matter' in data and data['matter']:
|
||||
matter = data['matter']
|
||||
matter.usage_budget += int(float(timeEntry.rate) * float(timeEntry.duration))
|
||||
matter.save()
|
||||
if matter.has_notify and matter.usage_budget >= matter.budget * (matter.notify_limit / 100):
|
||||
sendBudgetLimitWarning.delay(matter_id=matter.id)
|
||||
return timeEntry
|
||||
|
||||
@staticmethod
|
||||
def Remove(request, _id):
|
||||
timeEntry = TimeEntry.List(request).get(pk=_id)
|
||||
timeEntry.is_removed = True
|
||||
timeEntry.save()
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=timeEntry,
|
||||
action=Timeline.Action.REMOVE,
|
||||
message=None)
|
||||
return timeEntry
|
||||
|
||||
@staticmethod
|
||||
def List(request, inIsRemoved=False):
|
||||
matterIds = Matter.GetReadableMatters(request.lawyerUser).values_list("id", flat=True)
|
||||
return TimeEntry.objects.filter(Q(matter__id__in=matterIds) | Q(creator__id=request.lawyerUser.id)).filter(
|
||||
is_removed=inIsRemoved).all()
|
||||
|
||||
@staticmethod
|
||||
def get_amount(entry):
|
||||
return float("{:.2f}".format(entry.duration * entry.rate))
|
||||
|
||||
|
||||
# دسته بندی Expense
|
||||
class ExpenseCategory(models.Model):
|
||||
SEARCH = ["name"]
|
||||
|
||||
class ExpenseType(models.IntegerChoices):
|
||||
DISBURSEMENT = 1,
|
||||
RECOVERIES = 2,
|
||||
|
||||
creator = models.ForeignKey(LawyerUser, on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=32)
|
||||
rate = models.FloatField(default=0)
|
||||
expense_type = models.IntegerField(choices=ExpenseType.choices)
|
||||
is_removed = models.BooleanField(default=False)
|
||||
|
||||
def ToDict(self):
|
||||
modelDict = model_to_dict(self)
|
||||
modelDict["creator"] = self.creator.ToDict()
|
||||
modelDict["vendor"] = self.creator.ToDict()
|
||||
return modelDict
|
||||
|
||||
@staticmethod
|
||||
def GetValidatedDataFromRequest(request):
|
||||
data = request.bodyDict
|
||||
data["creator"] = request.lawyerUser
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def Create(request):
|
||||
print('hi')
|
||||
data = ExpenseCategory.GetValidatedDataFromRequest(request)
|
||||
expenseCategory = ExpenseCategory.objects.create(**data)
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=expenseCategory,
|
||||
action=Timeline.Action.CREATE,
|
||||
message=None)
|
||||
return expenseCategory
|
||||
|
||||
@staticmethod
|
||||
def Update(request, _id):
|
||||
data = ExpenseCategory.GetValidatedDataFromRequest(request)
|
||||
expenseCategory = ExpenseCategory.List(request).get(pk=_id)
|
||||
for key in data.keys():
|
||||
setattr(expenseCategory, key, data[key])
|
||||
expenseCategory.save()
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=expenseCategory,
|
||||
action=Timeline.Action.EDIT,
|
||||
message=None)
|
||||
return expenseCategory
|
||||
|
||||
@staticmethod
|
||||
def Remove(request, _id):
|
||||
expenseCategory = ExpenseCategory.List(request).get(pk=_id)
|
||||
expenseCategory.is_removed = True
|
||||
expenseCategory.save()
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=expenseCategory,
|
||||
action=Timeline.Action.REMOVE,
|
||||
message=None)
|
||||
return expenseCategory
|
||||
|
||||
@staticmethod
|
||||
def List(request, inIsRemoved=False):
|
||||
return ExpenseCategory.objects.filter(Q(creator__id=request.lawyerUser.GetMain().id) |
|
||||
Q(creator__main__id=request.lawyerUser.GetMain().id)).filter(
|
||||
is_removed=inIsRemoved).all()
|
||||
|
||||
|
||||
class ExpenseEntry(models.Model):
|
||||
SEARCH = ["matter__title"]
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
creator = models.ForeignKey(LawyerUser, on_delete=models.CASCADE, related_name="expense_entry_creator_set")
|
||||
user = models.ForeignKey(LawyerUser, on_delete=models.CASCADE, related_name="expense_entry_user_set")
|
||||
matter = models.ForeignKey(Matter, blank=True, null=True, on_delete=models.CASCADE)
|
||||
date = models.DateField(blank=True, null=True)
|
||||
|
||||
# اگر در فاکتور استفاده شده باشد True میشود چون فقط یکبار باید در فاکتور استفاده شود
|
||||
is_used_in_invoice = models.BooleanField(default=False)
|
||||
is_tax = models.BooleanField(default=False , null=True)
|
||||
|
||||
class ExpenseType(models.IntegerChoices):
|
||||
DISBURSEMENT = 1,
|
||||
RECOVERIES = 2,
|
||||
|
||||
expense_type = models.IntegerField(choices=ExpenseType.choices)
|
||||
category = models.ForeignKey(ExpenseCategory, blank=True, null=True, on_delete=models.CASCADE)
|
||||
# دقیق نمیدونم ولی فکر میکنم مثلا میگه این هزینه برای چه چیز فیزیکی یا ... استفاده شده - آقای کراری بهتر میدونند
|
||||
reference = models.CharField(max_length=32, blank=True, null=True)
|
||||
# تعداد - مثلا ۱۰ تا جعبه خریده شده
|
||||
quantity = models.IntegerField(default=1)
|
||||
|
||||
# تفاوت amount با rate رو نمیدونم. احتمالا آقای کراری از یکی استفاده کرده
|
||||
amount = models.FloatField(default=0)
|
||||
rate = models.FloatField(default=0)
|
||||
|
||||
# میشه به یک شخص هم نسبت پیدا کنه اما شاید بیشتر جنبه یادآوری داره
|
||||
vendor = models.ForeignKey(Contact, blank=True, null=True, on_delete=models.CASCADE)
|
||||
description = models.TextField(blank=True, null=True)
|
||||
is_removed = models.BooleanField(default=False)
|
||||
discount_cash = models.BigIntegerField(null=True)
|
||||
discount = models.IntegerField(null=True)
|
||||
@staticmethod
|
||||
def GetValidatedDataFromRequest(request):
|
||||
data = request.bodyDict
|
||||
if 'tax' in data:
|
||||
data.pop('tax')
|
||||
print(data)
|
||||
data["creator"] = request.lawyerUser
|
||||
|
||||
if "matter" in data and data["matter"] is not None:
|
||||
data["matter"] = Matter.GetReadableMatters(lawyerUser=request.lawyerUser).get(pk=data["matter"])
|
||||
|
||||
if "user" in data and data["user"] is not None:
|
||||
data["user"] = LawyerUser.GetReadableUsers(request.lawyerUser).get(pk=data["user"])
|
||||
|
||||
if "date" in data and data["date"] is not None:
|
||||
data["date"] = parse_date(request.Input("date"))
|
||||
|
||||
if "vendor" in data and data["vendor"] is not None:
|
||||
data["vendor"] = Contact.GetAccessibleContacts(request.lawyerUser).get(pk=data["vendor"])
|
||||
|
||||
if "category" in data and data["category"] is not None:
|
||||
data["category"] = ExpenseCategory.objects.get(pk=data["category"])
|
||||
if data["category"].creator.GetMain().id != data["creator"].GetMain().id:
|
||||
raise LawyerUser.NotOwnException
|
||||
|
||||
return data
|
||||
|
||||
def ToDict(self):
|
||||
modelDict = model_to_dict(self)
|
||||
modelDict["creator"] = self.creator.ToDict()
|
||||
if self.matter is not None:
|
||||
modelDict["matter"] = self.matter.ToDict()
|
||||
if self.user is not None:
|
||||
modelDict["user"] = self.user.ToDict()
|
||||
if self.category is not None:
|
||||
modelDict["category"] = self.category.ToDict()
|
||||
if self.vendor is not None:
|
||||
modelDict["vendor"] = self.vendor.ToDict()
|
||||
|
||||
return modelDict
|
||||
|
||||
@staticmethod
|
||||
def Create(request):
|
||||
data = ExpenseEntry.GetValidatedDataFromRequest(request)
|
||||
print(data)
|
||||
expenseEntry = ExpenseEntry.objects.create(**data)
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=expenseEntry,
|
||||
action=Timeline.Action.CREATE,
|
||||
message=None)
|
||||
if 'matter' in data and data['matter']:
|
||||
matter = data['matter']
|
||||
matter.usage_budget += float(data['amount'])
|
||||
matter.save()
|
||||
if matter.has_notify and matter.usage_budget >= matter.budget * (matter.notify_limit / 100):
|
||||
sendBudgetLimitWarning.delay(matter_id=matter.id)
|
||||
return expenseEntry
|
||||
|
||||
@staticmethod
|
||||
def Update(request, _id):
|
||||
data = ExpenseEntry.GetValidatedDataFromRequest(request)
|
||||
expenseEntry = ExpenseEntry.List(request).get(pk=_id)
|
||||
matter = data['matter']
|
||||
if 'matter' in data and data['matter']:
|
||||
matter.usage_budget -= expenseEntry.amount
|
||||
matter.save()
|
||||
for key in data.keys():
|
||||
setattr(expenseEntry, key, data[key])
|
||||
expenseEntry.save()
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=expenseEntry,
|
||||
action=Timeline.Action.EDIT,
|
||||
message=None)
|
||||
if 'matter' in data and data['matter']:
|
||||
matter = data['matter']
|
||||
matter.usage_budget += float(data['amount'])
|
||||
matter.save()
|
||||
if matter.has_notify and matter.usage_budget >= matter.budget * (matter.notify_limit / 100):
|
||||
sendBudgetLimitWarning.delay(matter_id=matter.id)
|
||||
return expenseEntry
|
||||
|
||||
@staticmethod
|
||||
def Remove(request, _id):
|
||||
expenseEntry = ExpenseEntry.List(request).get(pk=_id)
|
||||
expenseEntry.is_removed = True
|
||||
expenseEntry.save()
|
||||
Timeline.InsertEvent(lawyerUser=request.lawyerUser,
|
||||
row=expenseEntry,
|
||||
action=Timeline.Action.REMOVE,
|
||||
message=None)
|
||||
return expenseEntry
|
||||
|
||||
@staticmethod
|
||||
def List(request, inIsRemoved=False):
|
||||
matterIds = Matter.GetReadableMatters(request.lawyerUser).values_list("id", flat=True)
|
||||
return ExpenseEntry.objects.filter(Q(matter__id__in=matterIds) | Q(creator__id=request.lawyerUser.id)).filter(
|
||||
is_removed=inIsRemoved).all()
|
||||
|
||||
|
||||
@shared_task
|
||||
def sendBudgetLimitWarning(matter_id):
|
||||
matter = Matter.objects.get(pk=matter_id)
|
||||
for lawyer in matter.notifications.all():
|
||||
apps, in_mail = async_to_sync(CheckUserNotification)(user_id=lawyer.id, _type={"app": "is_budget_matter_in_app",
|
||||
"mobile": "is_budget_matter_in_mobile",
|
||||
"email": "is_budget_matter_in_email"})
|
||||
|
||||
if in_mail:
|
||||
_msg = Messenger.GenerateMessage(os.path.join(ROOT_DIR, "assets/verifies/part/budget-warning.html"),
|
||||
tokens={
|
||||
"lawyer_name": lawyer.first_name + ' ' + lawyer.last_name,
|
||||
"matter_name": matter.title,
|
||||
"matter_id": matter.id,
|
||||
"main_url": BASE_URL,
|
||||
})
|
||||
Messenger.SendMail.delay([lawyer.email_address],
|
||||
message=_msg,
|
||||
subject='Matter Budget Warning.',
|
||||
fromEmail=f'Budget Warning <no-reply@ira-lex.com>')
|
||||
|
||||
Messenger.SendFirebaseNotification.delay(
|
||||
title='Matter Budget Warning.',
|
||||
description=f'Your {matter.title} has been reached to the budget limit.',
|
||||
lawyerUserId=lawyer.id, apps=apps)
|
||||
return True
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from account.views import get_fullname
|
||||
from activity.models import TimeEntry, ExpenseEntry
|
||||
|
||||
|
||||
class TimeEntrySerializer(serializers.ModelSerializer):
|
||||
user_name = serializers.SerializerMethodField()
|
||||
|
||||
@staticmethod
|
||||
def get_user_name(obj):
|
||||
return get_fullname(obj.matter.responsible)
|
||||
|
||||
class Meta:
|
||||
model = TimeEntry
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class ExpenseEntrySerializer(serializers.ModelSerializer):
|
||||
user_name = serializers.SerializerMethodField()
|
||||
|
||||
@staticmethod
|
||||
def get_user_name(obj):
|
||||
return get_fullname(obj.matter.responsible)
|
||||
|
||||
class Meta:
|
||||
model = ExpenseEntry
|
||||
fields = '__all__'
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
from django.urls import path
|
||||
|
||||
from activity.views import *
|
||||
|
||||
urlpatterns = [
|
||||
path("time-entry/", CreateTimeEntry),
|
||||
path("time-entry/<int:_id>/", ByIdTimeEntry),
|
||||
path("time-entry/query/", QueryTimeEntry),
|
||||
|
||||
path("time-entry/category/", CreateTimeEntryCategory),
|
||||
path("time-entry/category/<int:_id>/", ByIdTimeEntryCategory),
|
||||
path("time-entry/category/query/", QueryTimeEntryCategory),
|
||||
|
||||
path("expense-entry/", CreateExpenseEntry),
|
||||
path("expense-entry/<int:_id>/", ByIdExpenseEntry),
|
||||
path("expense-entry/query/", QueryExpenseEntry),
|
||||
|
||||
path("expense-entry/category/", CreateExpenseCategory),
|
||||
path("expense-entry/category/<int:_id>/", ByIdExpenseCategory),
|
||||
path("expense-entry/category/query/", QueryExpenseCategory),
|
||||
|
||||
]
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
from account.Authentication import Authentication
|
||||
from activity.models import TimeEntry, ExpenseEntry, ExpenseCategory, TimeEntryCategory
|
||||
from core.filter_parser.FilterParser import FilterParser
|
||||
from core.utility.Response import Response
|
||||
from permission.permission_checker import Permissioner , Permissioner2
|
||||
from timeline.timeline import Timeline
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
@Permissioner.PermisionChecker("activity.time-entry.create")
|
||||
def CreateTimeEntry(request):
|
||||
timeEntry = TimeEntry.Create(request)
|
||||
return Response(timeEntry)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
@Permissioner2.PermisionChecker(["activity.time-entry.get","activity.time-entry.edit","activity.time-entry.delete"])
|
||||
def ByIdTimeEntry(request, _id):
|
||||
timeEntry = None
|
||||
|
||||
if request.method == "GET":
|
||||
timeEntry = TimeEntry.List(request).get(pk=_id)
|
||||
elif request.method == "PUT":
|
||||
timeEntry = TimeEntry.Update(request, _id)
|
||||
elif request.method == "DELETE":
|
||||
timeEntry = TimeEntry.Remove(request, _id)
|
||||
|
||||
return Response(timeEntry)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
@Permissioner.PermisionChecker("activity.time-entry.list")
|
||||
def QueryTimeEntry(request):
|
||||
return Response(FilterParser(request, TimeEntry.List(request), TimeEntry).Execute())
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def CreateTimeEntryCategory(request):
|
||||
timeEntryCategory = TimeEntryCategory.Create(request)
|
||||
return Response(timeEntryCategory)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def ByIdTimeEntryCategory(request, _id):
|
||||
timeEntryCategory = None
|
||||
|
||||
if request.method == "GET":
|
||||
timeEntryCategory = TimeEntryCategory.List(request).get(pk=_id)
|
||||
elif request.method == "PUT":
|
||||
timeEntryCategory = TimeEntryCategory.Update(request, _id)
|
||||
elif request.method == "DELETE":
|
||||
timeEntryCategory = TimeEntryCategory.Remove(request, _id)
|
||||
|
||||
return Response(timeEntryCategory)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def QueryTimeEntryCategory(request):
|
||||
return Response(FilterParser(request, TimeEntryCategory.List(request), TimeEntryCategory).Execute())
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
@Permissioner.PermisionChecker("activity.expense-entry.create")
|
||||
def CreateExpenseEntry(request):
|
||||
expenseEntry = ExpenseEntry.Create(request)
|
||||
return Response(expenseEntry)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
@Permissioner2.PermisionChecker(["activity.expense-entry.get" , "activity.expense-entry.edit" , "activity.expense-entry.delete"])
|
||||
def ByIdExpenseEntry(request, _id):
|
||||
expenseEntry = None
|
||||
|
||||
if request.method == "GET":
|
||||
expenseEntry = ExpenseEntry.List(request).get(pk=_id)
|
||||
elif request.method == "PUT":
|
||||
expenseEntry = ExpenseEntry.Update(request, _id)
|
||||
elif request.method == "DELETE":
|
||||
expenseEntry = ExpenseEntry.Remove(request, _id)
|
||||
|
||||
return Response(expenseEntry)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
@Permissioner.PermisionChecker("activity.expense-entry.list")
|
||||
def QueryExpenseEntry(request):
|
||||
return Response(FilterParser(request, ExpenseEntry.List(request), ExpenseEntry).Execute())
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
@Permissioner.PermisionChecker("activity.expense-entry.category.create")
|
||||
def CreateExpenseCategory(request):
|
||||
expenseCategory = ExpenseCategory.Create(request)
|
||||
return Response(expenseCategory)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
@Permissioner2.PermisionChecker(["activity.expense-entry.category.get" , "activity.expense-entry.category.edit" , "activity.expense-entry.category.delete"])
|
||||
def ByIdExpenseCategory(request, _id):
|
||||
expenseCategory = None
|
||||
|
||||
if request.method == "GET":
|
||||
expenseCategory = ExpenseCategory.List(request).get(pk=_id)
|
||||
elif request.method == "PUT":
|
||||
expenseCategory = ExpenseCategory.Update(request, _id)
|
||||
elif request.method == "DELETE":
|
||||
expenseCategory = ExpenseCategory.Remove(request, _id)
|
||||
|
||||
return Response(expenseCategory)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
@Permissioner.PermisionChecker("activity.expense-entry.category.list")
|
||||
def QueryExpenseCategory(request):
|
||||
return Response(FilterParser(request, ExpenseCategory.List(request), ExpenseCategory).Execute())
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AdminConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'administrator'
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
from hashlib import sha256
|
||||
|
||||
from django.core.management import BaseCommand
|
||||
|
||||
from account.models import LawyerUser
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "You can add super admin user with this command"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument("--email")
|
||||
parser.add_argument("--password")
|
||||
parser.add_argument("--first_name")
|
||||
parser.add_argument("--last_name")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
lawyerUser = LawyerUser.objects.create(
|
||||
email_address=options["email"],
|
||||
password=sha256(options["password"].encode("utf-8")).hexdigest(),
|
||||
first_name=options["first_name"],
|
||||
last_name=options["last_name"],
|
||||
is_verified=True,
|
||||
permission=LawyerUser.Permission.SUPER_ADMIN_PERMISSION)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f"User {lawyerUser.email_address} created ✅"))
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
from django.urls import path
|
||||
|
||||
from administrator.views import *
|
||||
|
||||
urlpatterns = [
|
||||
path("user/query/", QueryInUsers),
|
||||
path("user/query/deleted/", QueryInDeletedUsers),
|
||||
# path("user/<int:_id>/charge/", ChargeUser),
|
||||
path("hardware/", Hardware),
|
||||
path("user/application-admin/", CreateApplicationAdmin)
|
||||
|
||||
]
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
from hashlib import sha256
|
||||
|
||||
import psutil
|
||||
|
||||
from account.Authentication import Authentication
|
||||
from account.models import LawyerUser
|
||||
from core.filter_parser.FilterParser import FilterParser
|
||||
from core.utility.Response import Response
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def QueryInUsers(request):
|
||||
return Response(FilterParser(request, LawyerUser.objects.all(), LawyerUser).Execute())
|
||||
|
||||
#
|
||||
# @Authentication.Authenticate()
|
||||
# @Permission.Require(LawyerUser.Permission.APPLICATION_SUPER_ADMIN)
|
||||
# def ChargeUser(request, _id):
|
||||
# return Response(Subscription.Charge(request, _id))
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def CreateApplicationAdmin(request):
|
||||
lawyerUser = LawyerUser.objects.create(
|
||||
email_address=request.bodyDict["email"],
|
||||
password=sha256(
|
||||
request.bodyDict["password"].encode("utf-8")).hexdigest(),
|
||||
first_name=request.bodyDict["first_name"],
|
||||
last_name=request.bodyDict["last_name"],
|
||||
is_verified=True,
|
||||
# permission=LawyerUser.Permission.SUPER_ADMIN_PERMISSION #TODO : Add permission
|
||||
)
|
||||
|
||||
return Response(lawyerUser)
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def QueryInDeletedUsers(request):
|
||||
return Response(FilterParser(request, LawyerUser.objects.filter(is_removed=True), LawyerUser).Execute())
|
||||
|
||||
|
||||
@Authentication.Authenticate()
|
||||
def Hardware(request):
|
||||
psutilRam = psutil.virtual_memory()
|
||||
psutilDisk = psutil.disk_usage("/")
|
||||
|
||||
ram = {
|
||||
"total": psutilRam.total,
|
||||
"used": psutilRam.used,
|
||||
"percent": psutilRam.percent,
|
||||
"available": psutilRam.available,
|
||||
}
|
||||
|
||||
cpu = {
|
||||
"count": psutil.cpu_count(),
|
||||
"freq": psutil.cpu_freq(),
|
||||
"percent": psutil.cpu_percent(),
|
||||
}
|
||||
|
||||
disk = {
|
||||
"total": psutilDisk.total,
|
||||
"used": psutilDisk.used,
|
||||
"percent": psutilDisk.percent,
|
||||
"free": psutilDisk.free,
|
||||
|
||||
}
|
||||
|
||||
return Response({
|
||||
"ram": ram,
|
||||
"cpu": cpu,
|
||||
"disk": disk
|
||||
})
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head></head>
|
||||
<body>
|
||||
|
||||
<h2>Add Facebook Login to your webpage</h2>
|
||||
|
||||
<!-- Set the element id for the JSON response -->
|
||||
<p id="profile"></p>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// <!-- FB SDK LOAD START -->
|
||||
window.fbAsyncInit = function () {
|
||||
FB.init({
|
||||
appId: '1333717674102126',
|
||||
cookie: true,
|
||||
xfbml: true,
|
||||
version: 'v18.0'
|
||||
});
|
||||
FB.AppEvents.logPageView();
|
||||
};
|
||||
(function (d, s, id) {
|
||||
var js, fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)) {
|
||||
return;
|
||||
}
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = "https://connect.facebook.net/en_US/sdk.js";
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
}(document, 'script', 'facebook-jssdk'));
|
||||
// <!-- FB SDK LOAD END -->
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>$Title$</title>
|
||||
</head>
|
||||
<body>
|
||||
$END$
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Invoice</title>
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet"
|
||||
id="bootstrap-css">
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
|
||||
{style}
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; font-family: 'Montserrat', sans-serif;">
|
||||
<!-- HEADER -->
|
||||
<div style="background-image: url('https://ira-lex.com/app/download.png'); width: 100%; height: fit-content">
|
||||
<div style="text-align: center; color: rgba(0,0,0,.65); font-size: 48px; line-height: 48px; padding: 34px 0; border-bottom: 1px solid #e8e8e8;">
|
||||
INVOICE {invoice_no}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<!-- TITLE -->
|
||||
<table style="width: 100%; border-bottom: 1px solid #e8e8e8; padding: 24px 0;">
|
||||
<tr>
|
||||
<td style="text-align: left;">
|
||||
<img
|
||||
src="{avatar}"
|
||||
alt="Logo"
|
||||
style="width: 10rem; object-fit: contain;"
|
||||
>
|
||||
</td>
|
||||
<td style="text-align: right">
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 10px; line-height: 1;">Invoice Number:
|
||||
{invoice_no}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Invoice Date:
|
||||
{invoice_date}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Payment Due:
|
||||
{payment_date}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Reference Code:
|
||||
{reference_code}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- DATA -->
|
||||
<div style="width: 100%; display: flex; align-items: flex-start; justify-content: space-around ;">
|
||||
<div style="text-align: left; width: 50%;">
|
||||
<div style="margin-top: 24px; font-weight: 700; line-height: 21px; font-size: 12px;">
|
||||
{company_name}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Address:
|
||||
{company_address}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">City: {company_city}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">State:
|
||||
{company_state}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Post Code:
|
||||
{company_postalcode}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Country:
|
||||
{company_country}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Tel:
|
||||
{company_tel}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Fax: {company_fax}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Email:
|
||||
{company_mail}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Web: {company_site}
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: left ;width: 50%;">
|
||||
<div style="margin-top: 24px; font-weight: 700; line-height: 21px; font-size: 12px;">Client:
|
||||
{client_name}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Address:
|
||||
{client_address}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">City: {client_city}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">State:
|
||||
{client_state}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Country:
|
||||
{client_country}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Tel: {client_tel}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Email:
|
||||
{client_email}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Amount Due:
|
||||
{amount_due}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TABLE -->
|
||||
<table style="width: 100%; margin-top: 8px; border-collapse: collapse;">
|
||||
<tr style="background-color: #41438d; color: white;">
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Item No.</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Matter</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;word-break: break-all">
|
||||
Description
|
||||
</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Qty/Hr</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Unit Price</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Amount</th>
|
||||
</tr>
|
||||
{items}
|
||||
</table>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<div style="margin-left: auto; width: 50%; background-color: #fafafa; padding: 16px;">
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
Total:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{net_total}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
Discount:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{discount}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{sst_amount}% SST:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{sst}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; font-weight: 700; font-size: 12px; line-height: 1.5;">
|
||||
Total Amount:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; font-weight: 700; font-size: 12px; line-height: 1.5;">
|
||||
{total}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- NOTES -->
|
||||
<div id="notes">
|
||||
<p style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;">Notes:</p>
|
||||
<div style="color: #000000a6;font-size: 12px;">
|
||||
{company_description}
|
||||
</div>
|
||||
</div> <!-- END NOTES -->
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<tr>
|
||||
<td>{fundRequestDate}</td>
|
||||
<td>{fundRequestNote}</td>
|
||||
<td>{fundRequestTotal}</td>
|
||||
</tr>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<style>
|
||||
.logo {
|
||||
background-color: #3a3dbe;
|
||||
border-radius: 50%;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/google-oauth2.iml" filepath="$PROJECT_DIR$/.idea/google-oauth2.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta name="google-signin-client_id"
|
||||
content="986858475219-461v2efu5b1ghfsofnajak56pt806spa.apps.googleusercontent.com">
|
||||
|
||||
<script src="https://apis.google.com/js/platform.js" async defer></script>
|
||||
|
||||
<title>Login</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="g-signin2" data-onsuccess="onSignIn"></div>
|
||||
<script>
|
||||
function onSignIn(googleUser) {
|
||||
var profile = googleUser.getBasicProfile();
|
||||
console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
|
||||
console.log('Name: ' + profile.getName());
|
||||
console.log('Image URL: ' + profile.getImageUrl());
|
||||
console.log('Email: ' + profile.getEmail()); // This is null if the 'email' scope is not present.
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<style>
|
||||
@page {
|
||||
size: A4;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
Discount:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{discount}
|
||||
</div>
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Invoice</title>
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet"
|
||||
id="bootstrap-css">
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
|
||||
{style}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex">
|
||||
<div class="card-body p-0">
|
||||
<div class="row p-5">
|
||||
<div class="col-md-6">
|
||||
<!--img class="logo" width="100" height="100" src="https://ira-lex.com/img/iralex-logo.74718d06.svg"-->
|
||||
<img class="logo" width="100" height="100">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 text-right">
|
||||
<p class=" font-weight-bold mb-1">Invoice {invoiceId}</p>
|
||||
<div class="text-muted">Date: {curDate}</div>
|
||||
<div class="text-muted">Due On: {dueDate}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="">
|
||||
|
||||
<div class="row px-5 pt-4">
|
||||
<div class="col-md-6">
|
||||
<p class="h3 font-weight-bold mb-4">{legalName} Legal</p>
|
||||
<p class="mb-1">Client: {clientName}</p>
|
||||
<p>Matter(s)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row px-5 pt-4">
|
||||
<div class="col-md-12">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Row</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Title</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Quantity</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Hours</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{mainRows}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-end pr-5">
|
||||
<p class="h5">Total:</p>
|
||||
<p class="h5 ml-2">{total}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<hr class="mt-5"/>
|
||||
<!--
|
||||
<div class="">
|
||||
<p class="mt-5 h3 font-weight-bold mb-4 px-5">Detailed Statement of Account</p>
|
||||
<p class="px-5 h4">Other Invoices</p>
|
||||
<div class="row px-5 pt-4">
|
||||
<div class="col-md-12">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Invoice Number</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Due On</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Amount Due</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Payments Received</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Balance Due</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>3 </td>
|
||||
<td>12/21/2021</td>
|
||||
<td>MR40.00</td>
|
||||
<td>MR0.00</td>
|
||||
<td>MR40.00</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="">
|
||||
<p class="px-5 h4">Current Invoice</p>
|
||||
<div class="row px-5 pt-4">
|
||||
<div class="col-md-12">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Invoice Number</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Due On</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Amount Due</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Payments Received</th>
|
||||
<th class="border-0 text-uppercase small font-weight-bold">Balance Due</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>8</td>
|
||||
<td>12/21/2021</td>
|
||||
<td>MR220.00</td>
|
||||
<td>MR0.00</td>
|
||||
<td>MR22.00</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-end pr-5">
|
||||
<p class="h5">Outstanding Balance:</p>
|
||||
<p class="h5 ml-2">RM62</p>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end pr-5" >
|
||||
<p class="h5">Total Amount Outstanding:</p>
|
||||
<p class="h5 ml-2">RM62</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
|
||||
<div class="d-flex flex-col text-white px-5 pt-16 mt-5" style="background: #3a3dbe">
|
||||
<div class="py-3 px-5">
|
||||
<div class="mb-2">Please make all amounts payable to: {legalName} Legal</div>
|
||||
<!--<div class="font-weight-light">Please pay within 30 days.</div>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-light mt-5 mb-5 text-center small">invoice template by : <a class="text-light" target="_blank"
|
||||
href="http://totoprayogo.com">totoprayogo.com</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<tr>
|
||||
<td>{matterRowNumber}</td>
|
||||
<td>{matterTitle}</td>
|
||||
<td>{matterQuantity}</td>
|
||||
<td>{matterHours}</td>
|
||||
<td>{matterTotal}</td>
|
||||
</tr>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<style>
|
||||
.logo {
|
||||
background-color: #3a3dbe;
|
||||
border-radius: 50%;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<tr>
|
||||
<td style="padding: 16px; border-bottom: 1px solid #80808030;font-size: 12px !important;">{item_no}</td>
|
||||
<td style="padding: 16px; border-bottom: 1px solid #80808030;font-size: 12px !important;">{item_matter}</td>
|
||||
<td style="padding: 16px; border-bottom: 1px solid #80808030;font-size: 12px !important;"><h3>
|
||||
{item_category}
|
||||
</h3>
|
||||
{item_description}
|
||||
</td>
|
||||
<td style="padding: 16px; border-bottom: 1px solid #80808030;font-size: 12px !important;">{item_qt}</td>
|
||||
<td style="padding: 16px; border-bottom: 1px solid #80808030;font-size: 12px !important;">{unit_price}</td>
|
||||
<td style="padding: 16px; border-bottom: 1px solid #80808030;font-size: 12px !important;">{unit_amount}</td>
|
||||
</tr>
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap">
|
||||
|
||||
<title></title>
|
||||
</head>
|
||||
<body style="margin: 0; padding-inline: 15px; padding-block: 0; font-family: 'Montserrat', sans-serif;">
|
||||
<!-- HEADER -->
|
||||
<div style="background-image: url('https://ira-lex.com/app/download.png'); width: 100%; height: fit-content">
|
||||
<div style="text-align: center; color: rgba(0,0,0,.65); font-size: 48px; line-height: 48px; padding: 34px 0; border-bottom: 1px solid #e8e8e8;">
|
||||
{title} {invoice_no}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<!-- TITLE -->
|
||||
<table style="width: 100%; border-bottom: 1px solid #e8e8e8; padding: 24px 0;">
|
||||
<tr>
|
||||
<td style="text-align: left;">
|
||||
<img
|
||||
src="{avatar}"
|
||||
alt="Logo"
|
||||
style="width: 10rem; object-fit: fill;"
|
||||
>
|
||||
</td>
|
||||
<td style="text-align: right">
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 10px; line-height: 1;">{type} Number:
|
||||
{invoice_no}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">{type} Date:
|
||||
{invoice_date}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Payment Due:
|
||||
{payment_date}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Our Reference:
|
||||
{reference_code}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- DATA -->
|
||||
<div style="width: 100%; display: flex; align-items: flex-start; justify-content: space-around ;">
|
||||
<div style="text-align: left; width: 50%;">
|
||||
<div style="margin-top: 24px; font-weight: 700; line-height: 21px; font-size: 12px;">
|
||||
{company_name}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Address:
|
||||
{company_address}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">City: {company_city}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">State:
|
||||
{company_state}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Post Code:
|
||||
{company_postalcode}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Country:
|
||||
{company_country}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Tel:
|
||||
{company_tel}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Fax: {company_fax}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Email:
|
||||
{company_mail}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Web: {company_site}
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: left ;width: 50%;">
|
||||
<div style="margin-top: 24px; font-weight: 700; line-height: 21px; font-size: 12px;">{Client_title}:
|
||||
{client_name}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Address:
|
||||
{client_address}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">City: {client_city}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">State:
|
||||
{client_state}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Country:
|
||||
{client_country}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Tel: {client_tel}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Email:
|
||||
{client_email}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Amount Due:
|
||||
{amount_due}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TABLE -->
|
||||
<table style="width: 100%; margin-top: 8px; border-collapse: collapse;">
|
||||
<tr style="background-color: #41438d; color: white;">
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Item No.</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Matter</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;word-break: break-all">
|
||||
Description
|
||||
</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Qty/Hr</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Unit Price</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Amount</th>
|
||||
</tr>
|
||||
{items}
|
||||
</table>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<div style="margin-left: auto; width: 50%; background-color: #fafafa; padding: 16px;">
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
Total:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{net_total}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
Discount:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{discount}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{sst_amount}% SST:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{sst}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; font-weight: 700; font-size: 12px; line-height: 1.5;">
|
||||
Total Amount:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; font-weight: 700; font-size: 12px; line-height: 1.5;">
|
||||
{total}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- NOTES -->
|
||||
<div id="notes">
|
||||
<p style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;">Notes:</p>
|
||||
<div style="color: #000000a6;font-size: 12px;">
|
||||
{company_description}
|
||||
</div>
|
||||
</div> <!-- END NOTES -->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap">
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body style="font-family: 'Montserrat', sans-serif;">
|
||||
<!-- HEADER -->
|
||||
<table style="color: white; border-collapse: collapse; border-spacing: 0; width: 100%;">
|
||||
<clogroup>
|
||||
<col style="background: #41438d;">
|
||||
<col style="background: #393a87;">
|
||||
</clogroup>
|
||||
<tr>
|
||||
<td style=" font-weight: 500;margin: 5rem; font-size: 1.875rem; padding: 1rem 0 0.75rem 2rem;">
|
||||
{title} {invoice_no}
|
||||
</td>
|
||||
<td style="text-align: center; width: 30%; margin-top:7rem" rowspan="2">
|
||||
<small>Amount Due</small>
|
||||
<p style="text-align: center; font-size: 1.5rem; font-weight: 500;">
|
||||
{amount_due}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="line-height: 1.5; padding: 0 0 1rem 2rem; font-weight: 500;">
|
||||
<small>{client_name}</small>
|
||||
</td>
|
||||
</tr>
|
||||
</table> <!-- END HEADER -->
|
||||
|
||||
|
||||
<!-- BODY -->
|
||||
<section style="padding: 1.5rem;">
|
||||
<!-- INVOICE INFO -->
|
||||
<table style="border-collapse: collapse;border-spacing: 0;width: 100%;">
|
||||
<tr>
|
||||
<td style="width: 50%;">
|
||||
<span style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;">{type} Number: </span>
|
||||
<span style="color: #000000a6;font-size: 0.875rem;">{invoice_no}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;">{type} Date: </span>
|
||||
<span style="color: #000000a6;font-size: 0.875rem;">{invoice_date}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;">Payment Due: </span>
|
||||
<span style="color: #000000a6;font-size: 0.875rem;">{payment_date}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;">Our Reference: </span>
|
||||
<span style="color: #000000a6;font-size: 0.875rem;">{reference_code}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table> <!-- END INVOICE INFO -->
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- DATA -->
|
||||
<table style="margin-bottom: 1rem;border-collapse: collapse;border-spacing: 0;width: 100%;">
|
||||
<tr>
|
||||
<td style="width: 50%;">
|
||||
<div style="color: #5e615e; line-height: 21px; font-weight: 700; font-size: 14px;">{company_name}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Address: {company_address}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">City: {company_city}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">State: {company_state}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Post Code: {company_postalcode}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Country: {company_country}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Tel: {company_tel}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Fax: {company_fax}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Email: {company_mail}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Web: {company_site}</div>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
<div style="color: #5e615e; line-height: 21px; font-weight: 700; font-size: 14px;">{Client_title}:
|
||||
{client_name}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Address: {client_address}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">City: {client_city}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">State: {client_state}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Country: {client_country}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Tel: {client_tel}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Email: {client_email}</div>
|
||||
<div style="color: #5e615e; font-size: 12px; line-height: 1.5;">Amount Due: {amount_due}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table> <!-- END DATA -->
|
||||
|
||||
|
||||
<!-- TABLE -->
|
||||
<table id="main-table"
|
||||
style="width: 100%; margin-top: 8px; border-collapse: collapse;padding: 12px; border-bottom: 1px solid #80808030;">
|
||||
<tr style="background-color: #41438d; color: white;">
|
||||
<th style="text-align: left; font-size: 12px;">Item No.</th>
|
||||
<th style="text-align: left; font-size: 12px;">Matter</th>
|
||||
<th style="text-align: left; font-size: 12px; word-break: break-all">Description</th>
|
||||
<th style="text-align: left;font-size: 12px;">Qty/Hr</th>
|
||||
<th style="text-align: left; font-size: 12px;">Unit Price</th>
|
||||
<th style="text-align: left; font-size: 12px;">Amount</th>
|
||||
</tr>
|
||||
{items}
|
||||
</table> <!-- END TABLE -->
|
||||
|
||||
<!-- TABLE FOOTER -->
|
||||
<div style="margin-left: auto; width: 50%; background-color: #fafafa; padding: 16px;">
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 14px; line-height: 1.5;">
|
||||
Total:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 14px; line-height: 1.5;">
|
||||
{net_total}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 14px; line-height: 1.5;">
|
||||
Discount:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 14px; line-height: 1.5;">
|
||||
{discount}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 14px; line-height: 1.5;">
|
||||
{sst_amount}% SST:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 14px; line-height: 1.5;">
|
||||
{sst}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; font-weight: 700; font-size: 14px; line-height: 1.5;">
|
||||
Total Amount:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; font-weight: 700; font-size: 14px; line-height: 1.5;">
|
||||
{total}
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- END TABLE FOOTER -->
|
||||
|
||||
<!-- NOTES -->
|
||||
<div id="notes">
|
||||
<p style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;">Notes:</p>
|
||||
<div style="color: #000000a6;font-size: 12px;">
|
||||
{company_description}
|
||||
</div>
|
||||
</div> <!-- END NOTES -->
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<table style="border-collapse: collapse;border-spacing: 0;width: 100%;">
|
||||
<tr>
|
||||
<td>
|
||||
<img src="{avatar}" alt="Logo" style="width: 6rem; object-fit:fill; margin-right: 10px">
|
||||
</td>
|
||||
<td>
|
||||
<p style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;padding-left:1rem">
|
||||
{company_name}</p>
|
||||
<p style="color: #000000a6;font-size: 0.575rem; padding-left: 1rem ">{company_address}</p>
|
||||
</td>
|
||||
<td>
|
||||
<p style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;">Contact Information</p>
|
||||
<p style="color: #000000a6;font-size: 0.575rem;">{company_tel}</p>
|
||||
<p style="color: #000000a6;font-size: 0.575rem;">{company_mail}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table> <!-- END FOOTER -->
|
||||
|
||||
</section> <!-- END BODY -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; font-family: 'Montserrat', sans-serif;">
|
||||
<div style="display: flex; flex-direction: row; ">
|
||||
<div style="background-image: url('https://ira-lex.com/app/temHeader.png'); background-repeat: no-repeat;background-size: cover; color: white; display: flex; justify-content: center ;width: 100%; height: fit-content">
|
||||
<p> {title} {invoice_no}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<!-- TITLE -->
|
||||
<div style="width: 100%; display: flex; align-items: flex-start; justify-content: space-around; margin-top: 3rem;">
|
||||
<div style="text-align: left; width: 50%;">
|
||||
<img
|
||||
src="{avatar}"
|
||||
alt="Logo"
|
||||
style="width: 10rem; object-fit: fill;"
|
||||
>
|
||||
</div>
|
||||
<div style="text-align: left; width: 50%;">
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{company_name}
|
||||
</div>
|
||||
<div>
|
||||
{company_address}
|
||||
</div>
|
||||
<div>
|
||||
{company_tel}
|
||||
</div>
|
||||
<div>
|
||||
{company_site}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="position: relative; margin: 3rem 0;">
|
||||
<div style="background: rgba(0,0,0,.1); width: 100%; height: 3px; position: absolute; top: 50%;">
|
||||
<!-- box-shadow: 0 2px 4px 0 rgba(0,0,0,.1) !important; -->
|
||||
</div>
|
||||
<div style="position: relative; width: 6rem; height: 6rem; margin: 0 auto; border-radius: 50%; background: #fff;">
|
||||
<!-- box-shadow: 0 2px 4px #999 -->
|
||||
<div style="margin: 0.25rem; border-radius: 50%; border: 1px dashed #3a3dbe;">
|
||||
<!-- box-shadow: 0 2px 4px #999; -->
|
||||
<span style="display: block; text-align: center; margin: 2.25rem auto;">{type}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="padding: 0 3rem; margin-top: 4rem;">
|
||||
<div style="width: 100%; display: flex; align-items: flex-start; justify-content: space-around ;">
|
||||
<div style="text-align: left; width: 50%;">
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5">
|
||||
{type} number : {invoice_no}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Payment Due:
|
||||
{payment_date}
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: left; width: 50%;">
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">{type} Date:
|
||||
{invoice_date}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Our Reference:
|
||||
{reference_code}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 1px; background: #e8e8e8; margin: 24px 0;"></div>
|
||||
|
||||
|
||||
<!-- DATA -->
|
||||
<div style="width: 100%; display: flex; align-items: flex-start; justify-content: space-around ;">
|
||||
<div style="text-align: left; width: 50%;">
|
||||
<div style="margin-top: 24px; font-weight: 700; line-height: 21px; font-size: 12px;">
|
||||
{company_name}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Address:
|
||||
{company_address}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">City: {company_city}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">State:
|
||||
{company_state}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Post Code:
|
||||
{company_postalcode}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Country:
|
||||
{company_country}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Tel:
|
||||
{company_tel}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Fax: {company_fax}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Email:
|
||||
{company_mail}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Web: {company_site}
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: left ;width: 50%;">
|
||||
<div style="margin-top: 24px; font-weight: 700; line-height: 21px; font-size: 12px;">{Client_title}:
|
||||
{client_name}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Address:
|
||||
{client_address}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">City: {client_city}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">State:
|
||||
{client_state}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Country:
|
||||
{client_country}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Tel: {client_tel}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Email:
|
||||
{client_email}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">Amount Due:
|
||||
{amount_due}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TABLE -->
|
||||
<table style="width: 100%; margin-top: 8px; border-collapse: collapse;">
|
||||
<tr style="background-color: #41438d; color: white;">
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Item No.</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Matter</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;word-break: break-all">
|
||||
Description
|
||||
</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Qty/Hr</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Unit Price</th>
|
||||
<th style="text-align: left; padding: 10px 12px;font-size: 12px !important;">Amount</th>
|
||||
</tr>
|
||||
{items}
|
||||
</table>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<div style="margin-left: auto; width: 50%; background-color: #fafafa; padding: 16px;">
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
Total:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{net_total}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
Discount:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{discount}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{sst_amount}% SST:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{sst}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block; width: 49%; text-align: left; font-weight: 700; font-size: 12px; line-height: 1.5;">
|
||||
Total Amount:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; font-weight: 700; font-size: 12px; line-height: 1.5;">
|
||||
{total}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- NOTES -->
|
||||
<div id="notes">
|
||||
<p style="color: #000000d9;font-size: 0.875rem;margin-right: 0.2rem;">Notes:</p>
|
||||
<div style="color: #000000a6;font-size: 12px;">
|
||||
{company_description}
|
||||
</div>
|
||||
</div> <!-- END NOTES -->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; font-family: 'Montserrat', sans-serif;">
|
||||
|
||||
<img src="{avatar}" alt="Logo" style="object-fit: contain; width: 10rem; height: 65px; display: block; margin: 0 auto;">
|
||||
|
||||
|
||||
<h4 style="text-align: center; font-weight: 700; color: #000000a6;">{company_name}</h4>
|
||||
<h5 style="max-width: 500px; text-align: center; margin: 0 auto; color: #000000a6;">{company_address}</h5>
|
||||
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<td style="text-align: center; width: 50%; font-size: 14px; color: #000000a6;">
|
||||
Email: {company_mail}
|
||||
</td>
|
||||
<td style="text-align: center; width: 50%; font-size: 14px; color: #000000a6;">
|
||||
Tel: {company_tel}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3 style="margin-top: 2.5rem; margin-bottom: 0.5rem; text-align: center;">OFFICIAL RECEIPT</h3>
|
||||
|
||||
<!-- DATA -->
|
||||
<table style="width: 100%; margin-bottom: 1rem;">
|
||||
<tr>
|
||||
<td style="width: 70%;">
|
||||
<div style="color: #5e615e; line-height: 21px; font-weight: 700; font-size: 14px;">Received From:
|
||||
{receive_from}
|
||||
</div>
|
||||
<div style="color: #5e615e; font-size: 14px; line-height: 1.5;">{client_address1}</div>
|
||||
<div style="color: #5e615e; font-size: 14px; line-height: 1.5;">{client_address2}</div>
|
||||
<div style="color: #5e615e; font-size: 14px; line-height: 1.5;">Payment For: Invoice {invoice_no}</div>
|
||||
<div style="color: #5e615e; font-size: 14px; line-height: 1.5;">Remark: {remark}</div>
|
||||
</td>
|
||||
<td style="padding-left: 0.25rem; width: 30%; vertical-align: top;">
|
||||
<div style="color: #5e615e; font-size: 14px; line-height: 1.5;">Receipt No: OR00{receipt_no}</div>
|
||||
<div style="color: #5e615e; font-size: 14px; line-height: 1.5;">Date: {receipt_date}</div>
|
||||
<div style="color: #5e615e; font-size: 14px; line-height: 1.5;">Payment Type: {payment_type}</div>
|
||||
<div style="color: #5e615e; font-size: 14px; line-height: 1.5;">Bank in Date: {receipt_bank_date}</div>
|
||||
<div style="color: #5e615e; font-size: 14px; line-height: 1.5;">Amount :{amount}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table> <!-- END DATA -->
|
||||
|
||||
<!-- Price -->
|
||||
<hr style="margin-top: 40px;">
|
||||
<div style="margin-top: 1.2rem; display: inline-flex; justify-content: space-between;">
|
||||
<div style="">{char_amount}</div>
|
||||
<div style="display: inline-flex;"><div style="font-weight: bold;">Amount :</div>
|
||||
<div>{amount}</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<div style="display: inline-block; width: 49%; text-align: left; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{sst_amount}% SST:
|
||||
</div>
|
||||
<div style="display: inline-block; width: 49%; text-align: right; color: #5e615e; font-weight: 400; font-size: 12px; line-height: 1.5;">
|
||||
{sst}
|
||||
</div>
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
<style>
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
|
||||
/* What it does: Fixes webkit padding issue. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
/* What it does: Prevents Windows 10 Mail from underlining links despite inline CSS. Styles for underlined links should be inline. */
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.unstyle-auto-detected-links *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
|
||||
/* What it does: Prevents Gmail from displaying a download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
|
||||
/* What it does: Prevents Gmail from changing the text color in conversation threads. */
|
||||
|
||||
.im {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* iPhone 4, 4S, 5, 5S, 5C, and 5SE */
|
||||
|
||||
@media only screen and (min-device-width: 320px) and (max-device-width: 374px) {
|
||||
u ~ div .email-container {
|
||||
min-width: 320px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* iPhone 6, 6S, 7, 8, and X */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
u ~ div .email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* iPhone 6+, 7+, and 8+ */
|
||||
|
||||
@media only screen and (min-device-width: 414px) {
|
||||
u ~ div .email-container {
|
||||
min-width: 414px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.primary {
|
||||
background: #30e3ca;
|
||||
}
|
||||
|
||||
.bg_white {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.bg_light {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.bg_black {
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.bg_dark {
|
||||
background: rgba(0, 0, 0, .8);
|
||||
}
|
||||
|
||||
.email-section {
|
||||
padding: 2.5em;
|
||||
}
|
||||
|
||||
/*BUTTON*/
|
||||
|
||||
.btn {
|
||||
padding: 10px 15px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn.btn-primary {
|
||||
border-radius: 5px;
|
||||
background: #3a3dbe;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.btn.btn-white {
|
||||
border-radius: 5px;
|
||||
background: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.btn.btn-white-outline {
|
||||
border-radius: 5px;
|
||||
background: transparent;
|
||||
border: 1px solid #fff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn.btn-black-outline {
|
||||
border-radius: 0px;
|
||||
background: transparent;
|
||||
border: 2px solid #000;
|
||||
color: #000;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: 'Lato', sans-serif;
|
||||
color: #000000;
|
||||
margin-top: 0;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Lato', sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
line-height: 1.8;
|
||||
color: rgba(0, 0, 0, .4);
|
||||
}
|
||||
|
||||
a {
|
||||
color: #30e3ca;
|
||||
}
|
||||
|
||||
table {
|
||||
}
|
||||
|
||||
/*LOGO*/
|
||||
|
||||
.logo h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.logo h1 a {
|
||||
color: #30e3ca;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
font-family: 'Lato', sans-serif;
|
||||
}
|
||||
|
||||
/*HERO*/
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.hero .text {
|
||||
color: rgba(0, 0, 0, .3);
|
||||
}
|
||||
|
||||
.hero .text h2 {
|
||||
color: #000;
|
||||
font-size: 40px;
|
||||
margin-bottom: 0;
|
||||
font-weight: 400;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.hero .text h3 {
|
||||
font-size: 24px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.hero .text h2 span {
|
||||
font-weight: 600;
|
||||
color: #30e3ca;
|
||||
}
|
||||
|
||||
/*HEADING SECTION*/
|
||||
|
||||
.heading-section {
|
||||
}
|
||||
|
||||
.heading-section h2 {
|
||||
color: #000000;
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.heading-section .subheading {
|
||||
margin-bottom: 20px !important;
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
color: rgba(0, 0, 0, .4);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.heading-section .subheading::after {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: -10px;
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: #30e3ca;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.heading-section-white {
|
||||
color: rgba(255, 255, 255, .8);
|
||||
}
|
||||
|
||||
.heading-section-white h2 {
|
||||
font-family: line-height: 1;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.heading-section-white h2 {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.heading-section-white .subheading {
|
||||
margin-bottom: 0;
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
color: rgba(255, 255, 255, .4);
|
||||
}
|
||||
|
||||
ul.social {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.social li {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/*FOOTER*/
|
||||
|
||||
.footer {
|
||||
border-top: 1px solid rgba(0, 0, 0, .05);
|
||||
color: rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
.footer .heading {
|
||||
color: #000;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.footer ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.footer ul li {
|
||||
list-style: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.footer ul li a {
|
||||
color: rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
<div style="display: none; font-size: 1px;max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden; mso-hide: all; font-family: sans-serif;">
|
||||
‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
|
||||
</div>
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td class="logo" style="text-align: center;">
|
||||
<h1>
|
||||
<a href="#">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt=""
|
||||
style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
|
||||
|
||||
</a>
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci4.googleusercontent.com/proxy/UMF8BOFy2GQHbjvPAShH5Ian8v99R82HSxMPaVI5tyeGwMWS9LjetVHiAZDMw3gXHGSAQd3dnQrlX00=s0-d-e1-ft#https://app.ira-lex.com/assets/email.png"
|
||||
alt="" style="width: 300px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<!--<h2>You are nearly there!</h2> -->
|
||||
<p> the new user <b>{name}</b> is here in with this phone number {phone} and this email
|
||||
{email}</p>
|
||||
<!-- <p><a href="#" class="btn btn-primary">CONFIRM EMAIL</a></p> -->
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software designed to
|
||||
help lawfirms handle day-to-day operations efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a
|
||||
href="tel:+601128018817">+6011 2801 8817</a></span></li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a></li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
<style>
|
||||
/* What it does: Remove spaces around the email design added by some email clients. */
|
||||
/* Beware: It can remove the padding / margin and add a background color to the compose a reply window. */
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0 auto !important;
|
||||
padding: 0 !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
/* What it does: Stops email clients resizing small text. */
|
||||
|
||||
* {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
/* What it does: Centers email on Android 4.4 */
|
||||
|
||||
div[style*="margin: 16px 0"] {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* What it does: Stops Outlook from adding extra spacing to tables. */
|
||||
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt !important;
|
||||
mso-table-rspace: 0pt !important;
|
||||
}
|
||||
|
||||
/* What it does: Fixes webkit padding issue. */
|
||||
|
||||
table {
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
table-layout: fixed !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
|
||||
/* What it does: Uses a better rendering method when resizing images in IE. */
|
||||
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
/* What it does: Prevents Windows 10 Mail from underlining links despite inline CSS. Styles for underlined links should be inline. */
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* What it does: A work-around for email clients meddling in triggered links. */
|
||||
|
||||
*[x-apple-data-detectors],
|
||||
/* iOS */
|
||||
|
||||
.unstyle-auto-detected-links *,
|
||||
.aBn {
|
||||
border-bottom: 0 !important;
|
||||
cursor: default !important;
|
||||
color: inherit !important;
|
||||
text-decoration: none !important;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
|
||||
/* What it does: Prevents Gmail from displaying a download button on large, non-linked images. */
|
||||
|
||||
.a6S {
|
||||
display: none !important;
|
||||
opacity: 0.01 !important;
|
||||
}
|
||||
|
||||
/* What it does: Prevents Gmail from changing the text color in conversation threads. */
|
||||
|
||||
.im {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
/* If the above doesn't work, add a .g-img class to any image in question. */
|
||||
|
||||
img.g-img + div {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* What it does: Removes right gutter in Gmail iOS app: https://github.com/TedGoas/Cerberus/issues/89 */
|
||||
/* Create one of these media queries for each additional viewport size you'd like to fix */
|
||||
/* iPhone 4, 4S, 5, 5S, 5C, and 5SE */
|
||||
|
||||
@media only screen and (min-device-width: 320px) and (max-device-width: 374px) {
|
||||
u ~ div .email-container {
|
||||
min-width: 320px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* iPhone 6, 6S, 7, 8, and X */
|
||||
|
||||
@media only screen and (min-device-width: 375px) and (max-device-width: 413px) {
|
||||
u ~ div .email-container {
|
||||
min-width: 375px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* iPhone 6+, 7+, and 8+ */
|
||||
|
||||
@media only screen and (min-device-width: 414px) {
|
||||
u ~ div .email-container {
|
||||
min-width: 414px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.primary {
|
||||
background: #30e3ca;
|
||||
}
|
||||
|
||||
.bg_white {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.bg_light {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.bg_black {
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.bg_dark {
|
||||
background: rgba(0, 0, 0, .8);
|
||||
}
|
||||
|
||||
.email-section {
|
||||
padding: 2.5em;
|
||||
}
|
||||
|
||||
/*BUTTON*/
|
||||
|
||||
.btn {
|
||||
padding: 10px 15px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn.btn-primary {
|
||||
border-radius: 5px;
|
||||
background: #3a3dbe;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.btn.btn-white {
|
||||
border-radius: 5px;
|
||||
background: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.btn.btn-white-outline {
|
||||
border-radius: 5px;
|
||||
background: transparent;
|
||||
border: 1px solid #fff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn.btn-black-outline {
|
||||
border-radius: 0px;
|
||||
background: transparent;
|
||||
border: 2px solid #000;
|
||||
color: #000;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: 'Lato', sans-serif;
|
||||
color: #000000;
|
||||
margin-top: 0;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Lato', sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
line-height: 1.8;
|
||||
color: rgba(0, 0, 0, .4);
|
||||
}
|
||||
|
||||
a {
|
||||
color: #30e3ca;
|
||||
}
|
||||
|
||||
table {
|
||||
}
|
||||
|
||||
/*LOGO*/
|
||||
|
||||
.logo h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.logo h1 a {
|
||||
color: #30e3ca;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
font-family: 'Lato', sans-serif;
|
||||
}
|
||||
|
||||
/*HERO*/
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.hero .text {
|
||||
color: rgba(0, 0, 0, .3);
|
||||
}
|
||||
|
||||
.hero .text h2 {
|
||||
color: #000;
|
||||
font-size: 40px;
|
||||
margin-bottom: 0;
|
||||
font-weight: 400;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.hero .text h3 {
|
||||
font-size: 24px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.hero .text h2 span {
|
||||
font-weight: 600;
|
||||
color: #30e3ca;
|
||||
}
|
||||
|
||||
/*HEADING SECTION*/
|
||||
|
||||
.heading-section {
|
||||
}
|
||||
|
||||
.heading-section h2 {
|
||||
color: #000000;
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.heading-section .subheading {
|
||||
margin-bottom: 20px !important;
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
color: rgba(0, 0, 0, .4);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.heading-section .subheading::after {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: -10px;
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: #30e3ca;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.heading-section-white {
|
||||
color: rgba(255, 255, 255, .8);
|
||||
}
|
||||
|
||||
.heading-section-white h2 {
|
||||
font-family: line-height: 1;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.heading-section-white h2 {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.heading-section-white .subheading {
|
||||
margin-bottom: 0;
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
color: rgba(255, 255, 255, .4);
|
||||
}
|
||||
|
||||
ul.social {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.social li {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/*FOOTER*/
|
||||
|
||||
.footer {
|
||||
border-top: 1px solid rgba(0, 0, 0, .05);
|
||||
color: rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
.footer .heading {
|
||||
color: #000;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.footer ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.footer ul li {
|
||||
list-style: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.footer ul li a {
|
||||
color: rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
<div style="display: none; font-size: 1px;max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden; mso-hide: all; font-family: sans-serif;">
|
||||
‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
|
||||
</div>
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td class="logo" style="text-align: center;">
|
||||
<h1>
|
||||
<a href="#">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt=""
|
||||
style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
|
||||
|
||||
</a>
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci4.googleusercontent.com/proxy/UMF8BOFy2GQHbjvPAShH5Ian8v99R82HSxMPaVI5tyeGwMWS9LjetVHiAZDMw3gXHGSAQd3dnQrlX00=s0-d-e1-ft#https://app.ira-lex.com/assets/email.png"
|
||||
alt="" style="width: 300px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<h2>You are nearly there!</h2>
|
||||
<p id="fullName">
|
||||
Hi {name}
|
||||
</p>
|
||||
<p>
|
||||
To finish setting up your account and start using IRALEX, confirm we’ve
|
||||
got the correct email for you.
|
||||
</p>
|
||||
<p><a href="{verifyLink}" class="btn btn-primary"
|
||||
style="background: #0000EE; color: #FFFFFF; border-radius: 10px; text-decoration: none; padding: 15px;">
|
||||
Verify your email</a></p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software designed to
|
||||
help lawfirms handle day-to-day operations efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a
|
||||
href="tel:+601128018817">+6011 2801 8817</a></span></li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a></li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
{content}
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<style>
|
||||
body {
|
||||
font-family: 'Nunito', sans-serif;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 1200px;
|
||||
}
|
||||
|
||||
.container img {
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.verify, .logo {
|
||||
margin-top: 5em !important;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.body, #fullName {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.btn_verify {
|
||||
background-color: #2a2899;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
transition: 0.5s ease;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn_verify:hover {
|
||||
opacity: 0.8;
|
||||
transition: 0.5s ease;
|
||||
}
|
||||
|
||||
.footer {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.logo_footer {
|
||||
margin-top: 2em !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
<div style="display: none; font-size: 1px;max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden; mso-hide: all; font-family: sans-serif;">
|
||||
‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
|
||||
</div>
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td class="logo" style="text-align: center;">
|
||||
<h1>
|
||||
<a href="#">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt=""
|
||||
style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
|
||||
|
||||
</a>
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci4.googleusercontent.com/proxy/UMF8BOFy2GQHbjvPAShH5Ian8v99R82HSxMPaVI5tyeGwMWS9LjetVHiAZDMw3gXHGSAQd3dnQrlX00=s0-d-e1-ft#https://app.ira-lex.com/assets/email.png"
|
||||
alt="" style="width: 300px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<h2>You are nearly there!</h2>
|
||||
<p id="fullName">
|
||||
Hi {name}
|
||||
</p>
|
||||
<p>
|
||||
kljvl
|
||||
To finish setting up your account and start using IRALEX, confirm we’ve
|
||||
got the correct email for you.
|
||||
</p>
|
||||
<p><a href="{verifyLink}" class="btn btn-primary"
|
||||
style="background: #0000EE; color: #FFFFFF; border-radius: 10px; text-decoration: none; padding: 15px;">
|
||||
dclkvkjlj</a></p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software designed to
|
||||
help lawfirms handle day-to-day operations efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a
|
||||
href="tel:+601128018817">+6011 2801 8817</a></span></li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a></li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt="" style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
|
||||
<img alt=""
|
||||
src="https://ira-lex.com/app/Reminders%20(1).png"
|
||||
style="width: 300px; max-width: 600px; height: auto; margin: auto; display: block;"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<h2>You forget your password</h2>
|
||||
<p id="fullName">
|
||||
Hi {name}
|
||||
</p>
|
||||
<p style="margin-bottom: 30px">
|
||||
We have received your request to reset your password in IraLex.Please click on
|
||||
the following link to enter a new password.
|
||||
</p>
|
||||
<p><a href="{verifyLink}" class="btn btn-primary"
|
||||
style="background: #0000EE; color: #FFFFFF; border-radius: 10px; text-decoration: none; padding: 15px;">
|
||||
Set New Password</a></p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software designed to
|
||||
help lawfirms handle day-to-day operations efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a
|
||||
href="tel:+601128018817">+6011 2801 8817</a></span></li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a></li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt="" style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
|
||||
<img src="https://ira-lex.com/app/Attached%20files-bro%20(1).png" alt="" style="width: 300px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<h2>You are nearly there!</h2>
|
||||
<p id="fullName">
|
||||
Dear {responsible_lawyer}
|
||||
</p>
|
||||
<p style="margin-bottom: 40px">
|
||||
A new document has been attached to {matter_name} matter by {creator_name}.
|
||||
</p>
|
||||
<p>
|
||||
<p><a href="{main_url}/document?mater_id={matter_id}"
|
||||
style="background: #0000EE; color: #FFFFFF; border-radius: 10px; text-decoration: none; padding: 15px;"
|
||||
class="btn btn-primary">View Docs</a></p>
|
||||
</a></p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software designed to
|
||||
help lawfirms handle day-to-day operations efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a
|
||||
href="tel:+601128018817">+6011 2801 8817</a></span></li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a></li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt="" style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="logo" style="text-align: center;">
|
||||
<h1>
|
||||
<img src="https://ira-lex.com/app/Attached%20files-bro%20(1).png"
|
||||
alt="" style="width: auto; height: auto; margin: auto; display: block;">
|
||||
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<h2>You are nearly there!</h2>
|
||||
<p id="fullName">
|
||||
Dear {user_name}
|
||||
<br>
|
||||
<br>
|
||||
{maker_name} invited you to an event.
|
||||
<br>
|
||||
<br>
|
||||
</p>
|
||||
<p style="margin-bottom: 40px">
|
||||
Start date : {start_date} - End date : {end_date}
|
||||
<br>
|
||||
Attendees : {attend_names}
|
||||
<br>
|
||||
Calender : {maker_name}
|
||||
</p>
|
||||
<p>
|
||||
<a href="{main_url}/calendar" class="btn btn-primary"
|
||||
style="background: #0000EE; color: #FFFFFF; border-radius: 10px; text-decoration: none; padding: 15px;">
|
||||
View Calender
|
||||
</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software designed to
|
||||
help lawfirms handle day-to-day operations efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a
|
||||
href="tel:+601128018817">+6011 2801 8817</a></span></li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a></li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt=""
|
||||
style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td class="logo" style="text-align: center;">
|
||||
<h1>
|
||||
<img src="https://ira-lex.com/app/Attached%20files-bro%20(1).png" alt="" style="width: 300px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
|
||||
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<h2>You are nearly there!</h2>
|
||||
<p id="fullName">
|
||||
Dear {contact_name}
|
||||
</p>
|
||||
<p style="margin-bottom: 40px">
|
||||
Your {matter_title} mater was created by {creator_name},your
|
||||
responsible lawyer is {responsible_lawyer}.
|
||||
</p>
|
||||
<p> Reference Code : <b>{ref_code}</b></p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0"
|
||||
width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software
|
||||
designed to help lawfirms handle day-to-day operations
|
||||
efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0"
|
||||
width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a
|
||||
href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a href="tel:+601128018817">+6011 2801 8817</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0"
|
||||
width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a>
|
||||
</li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt="" style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td class="logo" style="text-align: center;">
|
||||
<h1>
|
||||
<img src="https://ira-lex.com/app/Attached%20files-bro%20(1).png"
|
||||
alt="" style="width: auto; height: auto; margin: auto; display: block;">
|
||||
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<p id="fullName">
|
||||
Dear {responsible_lawyer}
|
||||
</p>
|
||||
<p style="margin-bottom: 40px">
|
||||
{matter_name} matter has been assigned to you by {creator_name}.
|
||||
</p>
|
||||
<p>
|
||||
<a style="background: #0000EE; color: #FFFFFF; border-radius: 10px; text-decoration: none; padding: 15px;"
|
||||
class="btn btn-primary" href="{main_url}/matters?id={matter_id}">
|
||||
View Matter
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software designed to
|
||||
help lawfirms handle day-to-day operations efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a
|
||||
href="tel:+601128018817">+6011 2801 8817</a></span></li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a></li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt="" style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ira-lex.com/app/Attached%20files-bro%20(1).png"
|
||||
alt="" style="width: auto; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<p id="fullName">
|
||||
Dear {invited_name}
|
||||
</p>
|
||||
<p style="margin-bottom: 40px">
|
||||
You've been assigned to {task_name} by {inviter_name}.
|
||||
</p>
|
||||
<p>
|
||||
<a style="background: #0000EE; color: #FFFFFF; border-radius: 10px; text-decoration: none; padding: 15px;"
|
||||
href="{main_url}/task/list?task_id={task_id}">
|
||||
|
||||
View Task
|
||||
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software designed to
|
||||
help lawfirms handle day-to-day operations efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a
|
||||
href="tel:+601128018817">+6011 2801 8817</a></span></li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a></li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- utf-8 works for most cases -->
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Forcing initial-scale shouldn't be necessary -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- Use the latest (edge) version of IE rendering engine -->
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!-- Disable auto-scale in iOS 10 Mail entirely -->
|
||||
<title>IRALEX email</title>
|
||||
<!-- The title tag shows in email notifications, like Android 4.4. -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
|
||||
<center style="width: 100%; background-color: #f1f1f1;">
|
||||
|
||||
<div style="max-width: 600px; margin: 0 auto;" class="email-container">
|
||||
<!-- BEGIN BODY -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 3em 0 2em 0;">
|
||||
<img src="https://ci3.googleusercontent.com/proxy/x3ocY0ISnAVX5bLWQ_SFLMFkuW31hX5OPBfAfUqnEvtjgsI8O-4XtrVut9XyZE0KrbVtdS8Bj0dIhQ=s0-d-e1-ft#https://app.ira-lex.com/assets/logo.png"
|
||||
alt="" style="width: 100px; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
|
||||
<img src="https://ira-lex.com/app/fine%20(1).png" alt=""
|
||||
style="width: auto; max-width: 600px; height: auto; margin: auto; display: block;">
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<tr>
|
||||
<td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text" style="padding: 0 2.5em; text-align: center;">
|
||||
<p id="fullName">
|
||||
Dear {lawyer_name}
|
||||
</p>
|
||||
<p style="margin-bottom: 40px">
|
||||
Your {matter_name} has been reached to the budget limit.
|
||||
</p>
|
||||
<p>
|
||||
<a style="background: #0000EE; color: #FFFFFF; border-radius: 10px; text-decoration: none; padding: 15px;"
|
||||
href="{main_url}/matters?id={matter_id}">
|
||||
|
||||
View Matter
|
||||
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end tr -->
|
||||
<!-- 1 Column Text + Button : END -->
|
||||
</table>
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"
|
||||
style="margin: auto;">
|
||||
<tr>
|
||||
<td valign="middle" class="bg_light footer email-section">
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">
|
||||
<h3 class="heading">About</h3>
|
||||
<p>IRALEX is a comprehensive legal practice management software designed to
|
||||
help lawfirms handle day-to-day operations efficiently.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 5px; padding-right: 5px;">
|
||||
<h3 class="heading">Contact Info</h3>
|
||||
<ul>
|
||||
<li><span class="text"><a href="https://goo.gl/maps/d7KHzKSme9yZ16Ds9">2B-5-8, Block B, Plaza Mont Kiara, No. 2, Jalan Kiara, Mont Kiara, 50480 Kuala Lumpur, Malaysia</a></span>
|
||||
</li>
|
||||
<li><span class="text"><a
|
||||
href="tel:+601128018817">+6011 2801 8817</a></span></li>
|
||||
<li><span class="text"><a href="mailto:info@ira-lex.com">info@ira-lex.com</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top" width="33.333%" style="padding-top: 20px;">
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-left: 10px;">
|
||||
<h3 class="heading">Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://ira-lex.com/">Home</a></li>
|
||||
<li><a href="https://ira-lex.com/aboutus">About</a></li>
|
||||
<li><a href="https://ira-lex.com/app/register">Sign Up</a></li>
|
||||
<li><a href="https://ira-lex.com/app/login">Login</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end: tr -->
|
||||
<tr>
|
||||
<td class="bg_light" style="text-align: center;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue