├── .editorconfig ├── .firebaserc ├── .gitignore ├── .vs ├── VSWorkspaceState.json ├── angular-erp-system │ └── v15 │ │ └── .suo └── slnx.sqlite ├── .vscode └── launch.json ├── README.md ├── angular.json ├── e2e ├── protractor.conf.js ├── src │ ├── app.e2e-spec.ts │ └── app.po.ts └── tsconfig.e2e.json ├── firebase.json ├── package-lock.json ├── package.json ├── src ├── app │ ├── app-routing.module.ts │ ├── app-translate.service.ts │ ├── app.component.css │ ├── app.component.html │ ├── app.component.ts │ ├── app.module.ts │ ├── app.service.ts │ ├── auth │ │ ├── auth-routing.module.ts │ │ ├── auth.module.ts │ │ ├── auth.service.ts │ │ ├── auth │ │ │ ├── auth.component.html │ │ │ ├── auth.component.sass │ │ │ ├── auth.component.spec.ts │ │ │ └── auth.component.ts │ │ ├── auth_provider.injection-token.ts │ │ ├── firestore.injection-token.ts │ │ ├── login │ │ │ ├── login.component.html │ │ │ ├── login.component.sass │ │ │ ├── login.component.spec.ts │ │ │ └── login.component.ts │ │ └── profile │ │ │ ├── profile.component.html │ │ │ ├── profile.component.sass │ │ │ ├── profile.component.spec.ts │ │ │ └── profile.component.ts │ ├── contractors │ │ ├── components │ │ │ ├── contractor-list │ │ │ │ ├── contractor-list.component.css │ │ │ │ ├── contractor-list.component.html │ │ │ │ └── contractor-list.component.ts │ │ │ └── contractor-page │ │ │ │ ├── contractor-page.component.css │ │ │ │ ├── contractor-page.component.html │ │ │ │ └── contractor-page.component.ts │ │ ├── contractors-routing.module.ts │ │ ├── contractors.module.ts │ │ ├── models │ │ │ └── contractor.ts │ │ └── services │ │ │ ├── contractor-section-view-model.service.ts │ │ │ ├── contractor-view-model.service.ts │ │ │ └── contractor.service.ts │ ├── core │ │ ├── components │ │ │ ├── base-detail │ │ │ │ ├── base-detail.component.css │ │ │ │ ├── base-detail.component.html │ │ │ │ └── base-detail.component.ts │ │ │ ├── base-page │ │ │ │ ├── base-page.component.css │ │ │ │ ├── base-page.component.html │ │ │ │ └── base-page.component.ts │ │ │ ├── base-section │ │ │ │ ├── base-section.component.css │ │ │ │ ├── base-section.component.html │ │ │ │ └── base-section.component.ts │ │ │ ├── drop-down-control │ │ │ │ ├── drop-down-control.component.css │ │ │ │ ├── drop-down-control.component.html │ │ │ │ └── drop-down-control.component.ts │ │ │ ├── lookup-control │ │ │ │ ├── lookup-control.component.css │ │ │ │ ├── lookup-control.component.html │ │ │ │ └── lookup-control.component.ts │ │ │ └── lookup-dialog │ │ │ │ ├── lookup-data.service.ts │ │ │ │ ├── lookup-dialog.component.css │ │ │ │ ├── lookup-dialog.component.html │ │ │ │ └── lookup-dialog.component.ts │ │ ├── core.module.ts │ │ ├── data.service.ts │ │ ├── decorators │ │ │ ├── enum.decorator.ts │ │ │ ├── method.decorator.ts │ │ │ ├── model.decorator.ts │ │ │ ├── property.decorator.ts │ │ │ └── view-model-action.decorator.ts │ │ ├── firebase │ │ │ ├── firebase.module.ts │ │ │ └── firebase.service.ts │ │ ├── models │ │ │ └── base.model.ts │ │ ├── services │ │ │ └── entity-schema-namager.service.ts │ │ ├── translate.service.ts │ │ └── view-models │ │ │ ├── base-detail-view-model.service.ts │ │ │ ├── base-page-view-model.service.ts │ │ │ ├── base-section-view-model.service.ts │ │ │ └── base-view-model.service.ts │ ├── customers │ │ ├── components │ │ │ ├── customer-list │ │ │ │ ├── customer-list.component.css │ │ │ │ ├── customer-list.component.html │ │ │ │ └── customer-list.component.ts │ │ │ └── customer-page │ │ │ │ ├── customer-page.component.css │ │ │ │ ├── customer-page.component.html │ │ │ │ └── customer-page.component.ts │ │ ├── customers-routing.module.ts │ │ ├── customers.module.ts │ │ ├── enums │ │ │ └── customer-type.enum.ts │ │ ├── models │ │ │ └── customer.ts │ │ └── services │ │ │ ├── customer-section-view-model.service.ts │ │ │ ├── customer-view-model.service.ts │ │ │ └── customer.service.ts │ ├── home │ │ ├── home.component.css │ │ ├── home.component.html │ │ └── home.component.ts │ ├── items │ │ ├── components │ │ │ ├── item-features │ │ │ │ ├── item-features.component.css │ │ │ │ ├── item-features.component.html │ │ │ │ └── item-features.component.ts │ │ │ ├── item-list │ │ │ │ ├── item-list.component.css │ │ │ │ ├── item-list.component.html │ │ │ │ └── item-list.component.ts │ │ │ └── item-page │ │ │ │ ├── item-page.component.css │ │ │ │ ├── item-page.component.html │ │ │ │ └── item-page.component.ts │ │ ├── enums │ │ │ ├── item-feature-type.enum.ts │ │ │ └── item-type.enum.ts │ │ ├── items-routing.module.ts │ │ ├── items.module.ts │ │ ├── models │ │ │ ├── item-feature.ts │ │ │ └── item.ts │ │ └── services │ │ │ ├── item-features-view-model.service.ts │ │ │ ├── item-section-view-model.service.ts │ │ │ ├── item-view-model.service.ts │ │ │ └── item.service.ts │ ├── orders │ │ ├── components │ │ │ ├── order-features │ │ │ │ ├── order-features.component.css │ │ │ │ ├── order-features.component.html │ │ │ │ └── order-features.component.ts │ │ │ ├── order-list │ │ │ │ ├── order-list.component.css │ │ │ │ ├── order-list.component.html │ │ │ │ └── order-list.component.ts │ │ │ └── order-page │ │ │ │ ├── order-page.component.css │ │ │ │ ├── order-page.component.html │ │ │ │ └── order-page.component.ts │ │ ├── enums │ │ │ ├── order-feature-type.enum.ts │ │ │ ├── order-status.enum.ts │ │ │ └── order-type.enum.ts │ │ ├── models │ │ │ ├── order-feature.ts │ │ │ └── order.ts │ │ ├── orders-routing.module.ts │ │ ├── orders.module.ts │ │ └── services │ │ │ ├── order-features-view-model.service.ts │ │ │ ├── order-section-view-model.service.ts │ │ │ ├── order-view-model.service.ts │ │ │ └── order.service.ts │ ├── stocks │ │ ├── components │ │ │ ├── stock-list │ │ │ │ ├── stock-list.component.css │ │ │ │ ├── stock-list.component.html │ │ │ │ └── stock-list.component.ts │ │ │ └── stock-page │ │ │ │ ├── stock-page.component.css │ │ │ │ ├── stock-page.component.html │ │ │ │ └── stock-page.component.ts │ │ ├── enums │ │ │ └── stock-status.enum.ts │ │ ├── models │ │ │ └── stock.ts │ │ ├── services │ │ │ ├── stock-section-view-model.service.ts │ │ │ ├── stock-view-model.service.ts │ │ │ └── stock.service.ts │ │ ├── stocks-routing.module.ts │ │ └── stocks.module.ts │ ├── stores │ │ ├── components │ │ │ ├── store-list │ │ │ │ ├── store-list.component.css │ │ │ │ ├── store-list.component.html │ │ │ │ └── store-list.component.ts │ │ │ └── store-page │ │ │ │ ├── store-page.component.css │ │ │ │ ├── store-page.component.html │ │ │ │ └── store-page.component.ts │ │ ├── enums │ │ │ └── store-type.enum.ts │ │ ├── models │ │ │ └── store.ts │ │ ├── services │ │ │ ├── store-section-view-model.service.ts │ │ │ ├── store-view-model.service.ts │ │ │ └── store.service.ts │ │ ├── stores-routing.module.ts │ │ └── stores.module.ts │ └── transactions │ │ ├── components │ │ ├── transaction-list │ │ │ ├── transaction-list.component.css │ │ │ ├── transaction-list.component.html │ │ │ └── transaction-list.component.ts │ │ └── transaction-page │ │ │ ├── transaction-page.component.css │ │ │ ├── transaction-page.component.html │ │ │ └── transaction-page.component.ts │ │ ├── enums │ │ ├── transaction-status.enum.ts │ │ └── transaction-type.enum.ts │ │ ├── models │ │ └── transaction.ts │ │ ├── services │ │ ├── transaction-section-view-model.service.ts │ │ ├── transaction-view-model.service.ts │ │ └── transaction.service.ts │ │ ├── transactions-routing.module.ts │ │ └── transactions.module.ts ├── assets │ ├── .gitkeep │ └── i18n │ │ ├── en-US.json │ │ ├── ru-RU.json │ │ └── ua-UK.json ├── browserslist ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── karma.conf.js ├── main.ts ├── polyfills.ts ├── styles.css ├── test.ts ├── tsconfig.app.json ├── tsconfig.spec.json └── tslint.json ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "angular-erp-system" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | .firebase/* 48 | firebase-debug.log 49 | -------------------------------------------------------------------------------- /.vs/VSWorkspaceState.json: -------------------------------------------------------------------------------- 1 | { 2 | "ExpandedNodes": [ 3 | "" 4 | ], 5 | "PreviewInSolutionExplorer": false 6 | } -------------------------------------------------------------------------------- /.vs/angular-erp-system/v15/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/.vs/angular-erp-system/v15/.suo -------------------------------------------------------------------------------- /.vs/slnx.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/.vs/slnx.sqlite -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:4201", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AngularErpSystem 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.3.8. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-erp-system": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/angular-erp-system", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "src/tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 27 | "src/styles.css" 28 | ], 29 | "scripts": [], 30 | "es5BrowserSupport": true 31 | }, 32 | "configurations": { 33 | "production": { 34 | "fileReplacements": [ 35 | { 36 | "replace": "src/environments/environment.ts", 37 | "with": "src/environments/environment.prod.ts" 38 | } 39 | ], 40 | "optimization": true, 41 | "outputHashing": "all", 42 | "sourceMap": false, 43 | "extractCss": true, 44 | "namedChunks": false, 45 | "aot": true, 46 | "extractLicenses": true, 47 | "vendorChunk": false, 48 | "buildOptimizer": true, 49 | "budgets": [ 50 | { 51 | "type": "initial", 52 | "maximumWarning": "2mb", 53 | "maximumError": "5mb" 54 | } 55 | ] 56 | } 57 | } 58 | }, 59 | "serve": { 60 | "builder": "@angular-devkit/build-angular:dev-server", 61 | "options": { 62 | "browserTarget": "angular-erp-system:build", 63 | "aot": true, 64 | "port": 4201 65 | }, 66 | "configurations": { 67 | "production": { 68 | "browserTarget": "angular-erp-system:build:production" 69 | } 70 | } 71 | }, 72 | "extract-i18n": { 73 | "builder": "@angular-devkit/build-angular:extract-i18n", 74 | "options": { 75 | "browserTarget": "angular-erp-system:build" 76 | } 77 | }, 78 | "test": { 79 | "builder": "@angular-devkit/build-angular:karma", 80 | "options": { 81 | "main": "src/test.ts", 82 | "polyfills": "src/polyfills.ts", 83 | "tsConfig": "src/tsconfig.spec.json", 84 | "karmaConfig": "src/karma.conf.js", 85 | "styles": [ 86 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 87 | "src/styles.css" 88 | ], 89 | "scripts": [], 90 | "assets": [ 91 | "src/favicon.ico", 92 | "src/assets" 93 | ] 94 | } 95 | }, 96 | "lint": { 97 | "builder": "@angular-devkit/build-angular:tslint", 98 | "options": { 99 | "tsConfig": [ 100 | "src/tsconfig.app.json", 101 | "src/tsconfig.spec.json" 102 | ], 103 | "exclude": [ 104 | "**/node_modules/**" 105 | ] 106 | } 107 | } 108 | } 109 | }, 110 | "angular-erp-system-e2e": { 111 | "root": "e2e/", 112 | "projectType": "application", 113 | "prefix": "", 114 | "architect": { 115 | "e2e": { 116 | "builder": "@angular-devkit/build-angular:protractor", 117 | "options": { 118 | "protractorConfig": "e2e/protractor.conf.js", 119 | "devServerTarget": "angular-erp-system:serve" 120 | }, 121 | "configurations": { 122 | "production": { 123 | "devServerTarget": "angular-erp-system:serve:production" 124 | } 125 | } 126 | }, 127 | "lint": { 128 | "builder": "@angular-devkit/build-angular:tslint", 129 | "options": { 130 | "tsConfig": "e2e/tsconfig.e2e.json", 131 | "exclude": [ 132 | "**/node_modules/**" 133 | ] 134 | } 135 | } 136 | } 137 | } 138 | }, 139 | "defaultProject": "angular-erp-system" 140 | } -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to angular-erp-system!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "dist/angular-erp-system", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-erp-system", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve --aot", 7 | "build": "ng build --aot", 8 | "deploy": "ng build --prod && firebase deploy", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "~8.2.5", 16 | "@angular/cdk": "~8.2.0", 17 | "@angular/common": "~8.2.5", 18 | "@angular/compiler": "~8.2.5", 19 | "@angular/core": "~8.2.5", 20 | "@angular/forms": "~8.2.5", 21 | "@angular/material": "^8.2.0", 22 | "@angular/platform-browser": "~8.2.5", 23 | "@angular/platform-browser-dynamic": "~8.2.5", 24 | "@angular/pwa": "^0.803.4", 25 | "@angular/router": "~8.2.5", 26 | "@angular/service-worker": "~8.2.5", 27 | "@ngx-translate/core": "^11.0.1", 28 | "@ngx-translate/http-loader": "^4.0.0", 29 | "firebase": "^6.6.1", 30 | "guid-typescript": "^1.0.9", 31 | "hammerjs": "^2.0.8", 32 | "reflect-metadata": "^0.1.13", 33 | "rxjs": "~6.4.0", 34 | "tslib": "^1.10.0", 35 | "zone.js": "~0.9.1" 36 | }, 37 | "devDependencies": { 38 | "@angular-devkit/build-angular": "~0.803.4", 39 | "@angular/cli": "~8.3.4", 40 | "@angular/compiler-cli": "~8.2.5", 41 | "@angular/language-service": "~8.2.5", 42 | "@types/node": "~8.9.4", 43 | "@types/jasmine": "~3.3.8", 44 | "@types/jasminewd2": "~2.0.3", 45 | "codelyzer": "^5.0.0", 46 | "jasmine-core": "~3.4.0", 47 | "jasmine-spec-reporter": "~4.2.1", 48 | "karma": "~4.1.0", 49 | "karma-chrome-launcher": "~2.2.0", 50 | "karma-coverage-istanbul-reporter": "~2.0.1", 51 | "karma-jasmine": "~2.0.1", 52 | "karma-jasmine-html-reporter": "^1.4.0", 53 | "protractor": "~5.4.0", 54 | "ts-node": "~7.0.0", 55 | "tslint": "~5.15.0", 56 | "typescript": "~3.5.3" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { HomeComponent } from './home/home.component'; 4 | 5 | const routes: Routes = [ 6 | { path: '', redirectTo: 'home', pathMatch: 'full' }, 7 | { path: 'home', component: HomeComponent }, 8 | { path: 'customers', loadChildren: './customers/customers.module#CustomersModule' }, 9 | { path: 'contractors', loadChildren: './contractors/contractors.module#ContractorsModule' }, 10 | { path: 'items', loadChildren: './items/items.module#ItemsModule' }, 11 | { path: 'orders', loadChildren: './orders/orders.module#OrdersModule' }, 12 | { path: 'stocks', loadChildren: './stocks/stocks.module#StocksModule' }, 13 | { path: 'stores', loadChildren: './stores/stores.module#StoresModule' }, 14 | { path: 'transactions', loadChildren: './transactions/transactions.module#TransactionsModule' }, 15 | { path: 'profile', loadChildren: './auth/auth.module#AuthModule' }, 16 | ]; 17 | 18 | @NgModule({ 19 | imports: [RouterModule.forRoot(routes)], 20 | exports: [RouterModule] 21 | }) 22 | export class AppRoutingModule { } 23 | -------------------------------------------------------------------------------- /src/app/app-translate.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { TranslateService } from '@ngx-translate/core'; 3 | 4 | @Injectable({ providedIn: 'root' }) 5 | export class AppTranslateService extends TranslateService {} 6 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- 1 | .app-container { 2 | display: flex; 3 | flex-direction: column; 4 | position: absolute; 5 | top: 0; 6 | bottom: 0; 7 | left: 0; 8 | right: 0; 9 | } 10 | 11 | .app-is-mobile .app-toolbar { 12 | position: fixed; 13 | /* Make sure the toolbar will stay on top of the content as it scrolls past. */ 14 | z-index: 2; 15 | } 16 | 17 | h1.app-app-name { 18 | margin-left: 8px; 19 | } 20 | 21 | .app-sidenav-container { 22 | /* When the sidenav is not fixed, stretch the sidenav container to fill the available space. This 23 | causes `` to act as our scrolling element for desktop layouts. */ 24 | flex: 1; 25 | } 26 | 27 | .app-is-mobile .app-sidenav-container { 28 | /* When the sidenav is fixed, don't constrain the height of the sidenav container. This allows the 29 | `` to be our scrolling element for mobile layouts. */ 30 | flex: 1 0 auto; 31 | } 32 | 33 | .active-link { 34 | background-color: rgba(0,0,0,.1) 35 | } 36 | .mat-nav-list { 37 | width: 240px; 38 | } 39 | 40 | .lang-control { 41 | width: 72px; 42 | font-size: medium 43 | } -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |

{{ 'common.app-title' | translate }}

5 |
6 |
7 | 8 | {{ lang.title }} 9 | 10 |
11 |
12 | 13 | 15 | 19 | 20 | {{nav.title | translate }} 26 | 27 | 28 | 29 | 30 |
31 | 32 |
33 |
34 |
35 |
-------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ChangeDetectorRef, OnDestroy, ViewChild, AfterViewInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { MatSnackBar, MatSidenav, SELECT_MULTIPLE_PANEL_PADDING_X } from '@angular/material'; 4 | import { MediaMatcher } from '@angular/cdk/layout'; 5 | import { TranslateService } from '@ngx-translate/core'; 6 | import { FormControl } from '@angular/forms'; 7 | 8 | @Component({ 9 | selector: 'app-root', 10 | templateUrl: './app.component.html', 11 | styleUrls: [ './app.component.css' ] 12 | }) 13 | export class AppComponent implements OnDestroy { 14 | 15 | @ViewChild('snav', { static: true }) snavRef: MatSidenav; 16 | 17 | mobileQuery: MediaQueryList; 18 | fillerContent = 'test'; 19 | fillerNav: Array<{ title: string, path: string}> = [ 20 | { title: 'common.menu.customers', path: 'customers' }, 21 | { title: 'common.menu.contractors', path: 'contractors' }, 22 | { title: 'common.menu.orders', path: 'orders' }, 23 | { title: 'common.menu.items', path: 'items' }, 24 | { title: 'common.menu.stores', path: 'stores' }, 25 | { title: 'common.menu.stocks', path: 'stocks' }, 26 | { title: 'common.menu.transactions', path: 'transactions' }, 27 | { title: 'common.menu.profile', path: 'profile' }, 28 | ]; 29 | langs: Array<{ title: string, value: string }> = [ 30 | { title: 'EN', value: 'en-US' }, 31 | { title: 'UA', value: 'ua-UK' }, 32 | { title: 'RU', value: 'ru-RU' }, 33 | ]; 34 | langControl = new FormControl(); 35 | 36 | private mobileQueryListener: (ev: MediaQueryListEvent) => void; 37 | 38 | constructor( 39 | changeDetectorRef: ChangeDetectorRef, 40 | media: MediaMatcher, 41 | private snackBar: MatSnackBar, 42 | private translate: TranslateService 43 | ) { 44 | this.mobileQuery = media.matchMedia('(max-width: 600px)'); 45 | this.mobileQueryListener = _ => changeDetectorRef.detectChanges(); 46 | this.mobileQuery.addEventListener('change', this.mobileQueryListener); 47 | this.setUpLang(); 48 | } 49 | 50 | ngOnDestroy(): void { 51 | this.mobileQuery.removeEventListener('change', this.mobileQueryListener); 52 | } 53 | 54 | openSnackBar(message: string, action: string = null) { 55 | this.snackBar.open(message, action, { 56 | duration: 2000, 57 | }); 58 | } 59 | 60 | navLinkClick() { 61 | if (this.mobileQuery.matches) { 62 | this.snavRef.close(); 63 | } 64 | } 65 | 66 | setUpLang() { 67 | let lang = 'en-US'; 68 | if (localStorage) { 69 | const prefLang = localStorage.getItem('lang'); 70 | if (prefLang) { 71 | lang = prefLang; 72 | this.translate.use(lang); 73 | } 74 | } 75 | this.translate.setDefaultLang('en-US'); 76 | this.langControl.setValue(lang); 77 | this.langControl.valueChanges.subscribe(l => this.onLangChange(l)); 78 | } 79 | 80 | onLangChange(lang: string) { 81 | if (localStorage) { 82 | localStorage.setItem('lang', lang); 83 | } 84 | this.translate.use(lang); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 3 | 4 | import { CoreModule } from './core/core.module'; 5 | import { AppRoutingModule } from './app-routing.module'; 6 | 7 | import { AppComponent } from './app.component'; 8 | 9 | import { CustomersModule } from './customers/customers.module'; 10 | import { ItemsModule } from './items/items.module'; 11 | import { OrdersModule } from './orders/orders.module'; 12 | import { StocksModule } from './stocks/stocks.module'; 13 | import { StoresModule } from './stores/stores.module'; 14 | import { TransactionsModule } from './transactions/transactions.module'; 15 | import { HomeComponent } from './home/home.component'; 16 | 17 | @NgModule({ 18 | imports: [ 19 | BrowserAnimationsModule, 20 | 21 | CoreModule, 22 | AppRoutingModule, 23 | 24 | CustomersModule, 25 | ItemsModule, 26 | OrdersModule, 27 | StocksModule, 28 | StoresModule, 29 | TransactionsModule 30 | ], 31 | declarations: [ AppComponent, HomeComponent ], 32 | bootstrap: [ AppComponent ] 33 | }) 34 | export class AppModule { } 35 | -------------------------------------------------------------------------------- /src/app/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, ApplicationRef } from '@angular/core'; 2 | import { BehaviorSubject, interval, concat } from 'rxjs'; 3 | // import { Platform } from '@angular/cdk/platform'; 4 | // import { SwUpdate } from '@angular/service-worker'; 5 | import { first } from 'rxjs/operators'; 6 | 7 | @Injectable({ providedIn: 'root' }) 8 | export class AppService { 9 | 10 | public loading$ = new BehaviorSubject(false); 11 | get loading(): boolean { 12 | return this.loading$.getValue(); 13 | } 14 | set loading(value: boolean) { 15 | this.loading$.next(value); 16 | } 17 | 18 | public mobileView$ = new BehaviorSubject(false); 19 | get mobileView(): boolean { 20 | return this.mobileView$.value; 21 | } 22 | set mobileView(value: boolean) { 23 | this.mobileView$.next(value); 24 | } 25 | 26 | /*get touchUI(): boolean { 27 | return this.platform.ANDROID || this.platform.IOS; 28 | }*/ 29 | 30 | public newVersionAvailable$ = new BehaviorSubject(false); 31 | get newVersionAvailable(): boolean { 32 | return this.newVersionAvailable$.getValue(); 33 | } 34 | 35 | constructor( 36 | // public platform: Platform, 37 | // private updates: SwUpdate, 38 | appRef: ApplicationRef 39 | ) { 40 | /*const appIsStable$ = appRef.isStable.pipe(first(isStable => isStable === true)); 41 | const intervalMs = 45 * 60 * 10000; // 45 minutes 42 | const interval$ = interval(intervalMs); // every 15 minutes 43 | const intervalAppIsStable$ = concat(appIsStable$, interval$); 44 | if (updates.isEnabled) { 45 | intervalAppIsStable$.subscribe(() => updates.checkForUpdate()); 46 | } 47 | updates.available.subscribe(_ => this.newVersionAvailable$.next(true));*/ 48 | } 49 | 50 | installUpdates() { 51 | /*if (!this.updates.isEnabled) { 52 | return; 53 | } 54 | this.updates.activateUpdate() 55 | .then( 56 | () => document.location.reload() 57 | );*/ 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/app/auth/auth-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { AuthComponent } from './auth/auth.component'; 4 | 5 | const routes: Routes = [ 6 | { path: '', component: AuthComponent, pathMatch: 'full' }, 7 | ]; 8 | 9 | @NgModule({ 10 | imports: [RouterModule.forChild(routes)], 11 | exports: [RouterModule], 12 | }) 13 | export class AuthRoutingModule { } 14 | -------------------------------------------------------------------------------- /src/app/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule, InjectionToken } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | 4 | import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core'; 5 | 6 | import { AuthComponent } from './auth/auth.component'; 7 | import { AuthRoutingModule } from './auth-routing.module'; 8 | import { LoginComponent } from './login/login.component'; 9 | import { ProfileComponent } from './profile/profile.component'; 10 | import { CoreModule, HttpLoaderFactory } from '../core/core.module'; 11 | import { CoreTranslateService } from '../core/translate.service'; 12 | 13 | @NgModule({ 14 | declarations: [AuthComponent, LoginComponent, ProfileComponent], 15 | imports: [ 16 | CoreModule, 17 | AuthRoutingModule, 18 | TranslateModule.forChild({ 19 | loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient] }, 20 | }), 21 | ], 22 | providers: [ 23 | { provide: TranslateService, useExisting: CoreTranslateService } 24 | ], 25 | }) 26 | export class AuthModule { } 27 | -------------------------------------------------------------------------------- /src/app/auth/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import { Observable, from } from 'rxjs'; 3 | import { AUTH_PROVIDER_INJECTION_TOKEN } from './auth_provider.injection-token'; 4 | import { FIRESTORE_INJECTION_TOKEN } from './firestore.injection-token'; 5 | import { MatSnackBar } from '@angular/material'; 6 | import { catchError } from 'rxjs/operators'; 7 | 8 | 9 | @Injectable({ providedIn: 'root' }) 10 | export class AuthService { 11 | 12 | private get auth() { 13 | return this.firestore.app.auth(); 14 | } 15 | get profile() { 16 | return this.auth.currentUser; 17 | } 18 | constructor( 19 | @Inject(FIRESTORE_INJECTION_TOKEN) protected firestore: firebase.firestore.Firestore, 20 | @Inject(AUTH_PROVIDER_INJECTION_TOKEN) protected provider: firebase.auth.AuthProvider, 21 | private snackbar: MatSnackBar 22 | ) {} 23 | 24 | logIn(): Observable { 25 | return from( 26 | this.auth.signInWithPopup(this.provider) 27 | ).pipe( 28 | catchError((err, caught) => { 29 | this.snackbar.open(err.message); 30 | console.error(err); 31 | return caught; 32 | }) 33 | ); 34 | } 35 | 36 | signOut() { 37 | return from(this.auth.signOut()); 38 | } 39 | 40 | getUsers() { 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/app/auth/auth/auth.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/app/auth/auth/auth.component.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/auth/auth/auth.component.sass -------------------------------------------------------------------------------- /src/app/auth/auth/auth.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AuthComponent } from './auth.component'; 4 | 5 | describe('AuthComponent', () => { 6 | let component: AuthComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AuthComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AuthComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/auth/auth/auth.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { AuthService } from '../auth.service'; 3 | 4 | @Component({ 5 | selector: 'app-auth', 6 | templateUrl: './auth.component.html', 7 | styleUrls: ['./auth.component.sass'] 8 | }) 9 | export class AuthComponent implements OnInit { 10 | 11 | get loggedIn(): boolean { 12 | return this.authSvc.profile !== null; 13 | } 14 | 15 | constructor(private authSvc: AuthService) { } 16 | 17 | ngOnInit() { 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/app/auth/auth_provider.injection-token.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | 3 | declare const firebase: any; 4 | 5 | export const AUTH_PROVIDER_INJECTION_TOKEN = new InjectionToken('auth_provider', { 6 | providedIn: 'root', 7 | factory: () => { 8 | const provider = new firebase.auth.GoogleAuthProvider(); 9 | provider.addScope('https://www.googleapis.com/auth/contacts.readonly'); 10 | return provider; 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /src/app/auth/firestore.injection-token.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | 3 | declare const firebase: any; 4 | 5 | const firebaseDefaultApp = firebase.app(); 6 | 7 | export const FIRESTORE_INJECTION_TOKEN = new InjectionToken('firestore', { 8 | providedIn: 'root', 9 | factory: () => firebaseDefaultApp.firestore() 10 | }); 11 | -------------------------------------------------------------------------------- /src/app/auth/login/login.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /src/app/auth/login/login.component.sass: -------------------------------------------------------------------------------- 1 | .content-wrap 2 | width: 100% 3 | display: flex 4 | justify-content: center 5 | align-items: center 6 | padding: 2rem -------------------------------------------------------------------------------- /src/app/auth/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/auth/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { AuthService } from '../auth.service'; 3 | import { AppService } from 'src/app/app.service'; 4 | import { take, finalize } from 'rxjs/operators'; 5 | 6 | @Component({ 7 | selector: 'app-login', 8 | templateUrl: './login.component.html', 9 | styleUrls: ['./login.component.sass'] 10 | }) 11 | export class LoginComponent implements OnInit { 12 | 13 | constructor( 14 | private authSvc: AuthService, 15 | private appSvc: AppService, 16 | ) { } 17 | 18 | ngOnInit() { 19 | } 20 | 21 | onLoginClick() { 22 | this.authSvc.logIn() 23 | .pipe( 24 | take(1), 25 | ) 26 | .subscribe( 27 | userCredential => null, 28 | e => console.error(e) 29 | ); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/app/auth/profile/profile.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 |
7 | 8 |
9 |
10 |
11 |
12 |
13 | 14 |
{{ profile.displayName }}
15 |
16 |
17 | 18 |
{{ profile.email }}
19 |
20 |
21 | 22 |
{{ profile.phoneNumber }}
23 |
24 |
25 |
26 |
27 | 28 | 29 | 30 |
31 | -------------------------------------------------------------------------------- /src/app/auth/profile/profile.component.sass: -------------------------------------------------------------------------------- 1 | .profile-item div[name="photo"] img 2 | width: 120px 3 | 4 | .wrap 5 | display: flex 6 | 7 | .col 8 | padding: 0 1rem 9 | 10 | .profile-info .profile-item 11 | padding: 0.33rem 0 -------------------------------------------------------------------------------- /src/app/auth/profile/profile.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProfileComponent } from './profile.component'; 4 | 5 | describe('ProfileComponent', () => { 6 | let component: ProfileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProfileComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProfileComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/auth/profile/profile.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { AuthService } from '../auth.service'; 3 | 4 | @Component({ 5 | selector: 'app-profile', 6 | templateUrl: './profile.component.html', 7 | styleUrls: ['./profile.component.sass'] 8 | }) 9 | export class ProfileComponent implements OnInit { 10 | 11 | get profile() { 12 | return this.authSvc.profile; 13 | } 14 | 15 | constructor( 16 | private authSvc: AuthService, 17 | ) { } 18 | 19 | ngOnInit() { 20 | } 21 | 22 | signOut() { 23 | this.authSvc.signOut().subscribe(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/app/contractors/components/contractor-list/contractor-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/contractors/components/contractor-list/contractor-list.component.css -------------------------------------------------------------------------------- /src/app/contractors/components/contractor-list/contractor-list.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/contractors/components/contractor-list/contractor-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import { DataService } from '../../../core/data.service'; 4 | import { BaseSectionViewModel } from '../../../core/view-models/base-section-view-model.service'; 5 | 6 | import { ContractorSectionViewModelService } from '../../services/contractor-section-view-model.service'; 7 | import { ContractorService } from '../../services/contractor.service'; 8 | 9 | @Component({ 10 | selector: 'app-contractor-list', 11 | templateUrl: './contractor-list.component.html', 12 | styleUrls: ['./contractor-list.component.css'], 13 | providers: [ 14 | { provide: BaseSectionViewModel, useClass: ContractorSectionViewModelService }, 15 | { provide: DataService, useClass: ContractorService } 16 | ] 17 | }) 18 | export class ContractorListComponent implements OnInit { 19 | 20 | constructor() { } 21 | 22 | ngOnInit() { 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/app/contractors/components/contractor-page/contractor-page.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/contractors/components/contractor-page/contractor-page.component.css -------------------------------------------------------------------------------- /src/app/contractors/components/contractor-page/contractor-page.component.html: -------------------------------------------------------------------------------- 1 | 2 | {{ 'contractors.contractor-page' | translate }} 3 | {{ vm.subTitle$ | async }} 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
45 |
-------------------------------------------------------------------------------- /src/app/contractors/components/contractor-page/contractor-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, OnDestroy } from '@angular/core'; 2 | 3 | import { DataService } from '../../../core/data.service'; 4 | import { ContractorViewModelService } from '../../services/contractor-view-model.service'; 5 | import { ContractorService } from '../../services/contractor.service'; 6 | 7 | @Component({ 8 | selector: 'app-contractor-page', 9 | templateUrl: './contractor-page.component.html', 10 | styleUrls: ['./contractor-page.component.css'], 11 | providers: [ 12 | ContractorViewModelService, 13 | { provide: DataService, useExisting: ContractorService } 14 | ] 15 | }) 16 | export class ContractorPageComponent implements OnInit, OnDestroy { 17 | 18 | constructor(public vm: ContractorViewModelService) { } 19 | 20 | ngOnInit() { 21 | this.vm.init(); 22 | } 23 | 24 | ngOnDestroy() { 25 | this.vm.dispose(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/app/contractors/contractors-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { ContractorListComponent } from './components/contractor-list/contractor-list.component'; 5 | import { ContractorPageComponent } from './components/contractor-page/contractor-page.component'; 6 | 7 | const routes: Routes = [ 8 | { path: '', component: ContractorListComponent, pathMatch: 'full' }, 9 | { path: 'new', component: ContractorPageComponent }, 10 | { path: 'edit/:id', component: ContractorPageComponent }, 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule], 16 | }) 17 | export class ContractorsRoutingModule {} 18 | -------------------------------------------------------------------------------- /src/app/contractors/contractors.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 4 | import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core'; 5 | 6 | import { CoreModule } from '../core/core.module'; 7 | import { AppTranslateService } from '../app-translate.service'; 8 | 9 | import { ContractorListComponent } from './components/contractor-list/contractor-list.component'; 10 | import { ContractorPageComponent } from './components/contractor-page/contractor-page.component'; 11 | import { ContractorsRoutingModule } from './contractors-routing.module'; 12 | 13 | export function HttpLoaderFactory(http: HttpClient) { 14 | return new TranslateHttpLoader(http); 15 | } 16 | 17 | @NgModule({ 18 | imports: [ 19 | CoreModule, 20 | ContractorsRoutingModule, 21 | TranslateModule.forChild({ 22 | loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient] }, 23 | }) 24 | ], 25 | declarations: [ContractorListComponent, ContractorPageComponent], 26 | providers: [ 27 | { provide: TranslateService, useExisting: AppTranslateService } 28 | ] 29 | }) 30 | export class ContractorsModule { } 31 | -------------------------------------------------------------------------------- /src/app/contractors/models/contractor.ts: -------------------------------------------------------------------------------- 1 | import { Model } from '../../core/decorators/model.decorator'; 2 | import { ModelProperty, DataValueType, DropDownConfig } from '../../core/decorators/property.decorator'; 3 | import { BaseModel } from '../../core/models/base.model'; 4 | import { Validators } from '@angular/forms'; 5 | 6 | @Model({ 7 | caption: 'contractors.title', 8 | name: 'Contractor', 9 | collectionName: 'contractors' 10 | }) 11 | export class Contractor extends BaseModel { 12 | 13 | @ModelProperty({ 14 | caption: 'common.id', 15 | dataValueType: DataValueType.Text, 16 | }) 17 | id: string; 18 | 19 | @ModelProperty({ 20 | caption: 'contractors.caption.name', 21 | dataValueType: DataValueType.Text, 22 | required: true 23 | }) 24 | name: string; 25 | 26 | @ModelProperty({ 27 | caption: 'contractors.caption.number', 28 | dataValueType: DataValueType.Text, 29 | readOnly: true, 30 | defaultValue: () => new Date().valueOf() 31 | }) 32 | number: string; 33 | 34 | @ModelProperty({ 35 | caption: 'contractors.caption.phone', 36 | dataValueType: DataValueType.Text, 37 | validators: [Validators.pattern(/^0\d{9}$/)], 38 | required: true 39 | }) 40 | phone: string; 41 | 42 | @ModelProperty({ 43 | caption: 'contractors.caption.email', 44 | dataValueType: DataValueType.Text, 45 | validators: [Validators.email] 46 | }) 47 | email: string; 48 | 49 | @ModelProperty({ 50 | caption: 'contractors.caption.address', 51 | dataValueType: DataValueType.Text 52 | }) 53 | address: string; 54 | 55 | @ModelProperty({ 56 | caption: 'contractors.caption.notes', 57 | dataValueType: DataValueType.RichText 58 | }) 59 | notes: string; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/app/contractors/services/contractor-section-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { BaseSectionViewModel } from '../../core/view-models/base-section-view-model.service'; 2 | import { Injectable, Inject, Injector } from '@angular/core'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class ContractorSectionViewModelService extends BaseSectionViewModel { 8 | 9 | displayedColumns: string[] = ['number', 'name', 'phone', 'email', 'address', 'menu']; 10 | entitySchemaName = 'Contractor'; 11 | 12 | constructor(@Inject(Injector) injector: Injector) { 13 | super(injector); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/contractors/services/contractor-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Injector, Inject } from '@angular/core'; 2 | import { BasePageViewModel } from '../../core/view-models/base-page-view-model.service'; 3 | import { Observable } from 'rxjs'; 4 | import { Contractor } from '../models/contractor'; 5 | import { ContractorService } from './contractor.service'; 6 | 7 | @Injectable() 8 | export class ContractorViewModelService extends BasePageViewModel { 9 | 10 | protected entitySchemaName = 'Contractor'; 11 | protected entity = new Contractor(); 12 | 13 | public get subTitle$(): Observable { 14 | return this.id 15 | ? this.translate.get('common.edit', { value: this.entity && this.entity.name }) 16 | : this.translate.get('common.create-new'); 17 | } 18 | 19 | constructor(@Inject(Injector) injector: Injector, protected contractorService: ContractorService) { 20 | super(injector); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/app/contractors/services/contractor.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { DataService } from '../../core/data.service'; 3 | import { Contractor } from '../models/contractor'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class ContractorService extends DataService { 7 | 8 | collectionName = 'contractors'; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/core/components/base-detail/base-detail.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/core/components/base-detail/base-detail.component.css -------------------------------------------------------------------------------- /src/app/core/components/base-detail/base-detail.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ vm.subTitle$ | async }} 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |
14 | 15 | 16 | 19 | 20 | 21 |
-------------------------------------------------------------------------------- /src/app/core/components/base-detail/base-detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | import { FormArray } from '@angular/forms'; 3 | import { BaseDetailViewModelService } from '../../view-models/base-detail-view-model.service'; 4 | 5 | @Component({ 6 | selector: 'app-base-detail', 7 | templateUrl: './base-detail.component.html', 8 | styleUrls: ['./base-detail.component.css'] 9 | }) 10 | export class BaseDetailComponent implements OnInit { 11 | 12 | @Input() 13 | formArray: FormArray; 14 | 15 | constructor(public vm: BaseDetailViewModelService) { } 16 | 17 | ngOnInit() { 18 | this.vm.formArray = this.formArray; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/core/components/base-page/base-page.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/core/components/base-page/base-page.component.css -------------------------------------------------------------------------------- /src/app/core/components/base-page/base-page.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 24 |
25 |
26 | 30 | 31 | 35 | 36 |
37 |
38 |
39 |
-------------------------------------------------------------------------------- /src/app/core/components/base-page/base-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Output, EventEmitter, Input, Optional } from '@angular/core'; 2 | import { Location } from '@angular/common'; 3 | 4 | import { BasePageViewModel } from '../../view-models/base-page-view-model.service'; 5 | 6 | @Component({ 7 | selector: 'app-base-page', 8 | templateUrl: './base-page.component.html', 9 | styleUrls: ['./base-page.component.css'] 10 | }) 11 | export class BasePageComponent implements OnInit { 12 | 13 | @Input() saveButtonDisabled: boolean; 14 | @Input() saveButtonHidden: boolean; 15 | 16 | @Output() save = new EventEmitter(); 17 | 18 | constructor( 19 | @Optional() public vm: BasePageViewModel, 20 | private location: Location, 21 | ) { } 22 | 23 | ngOnInit() { 24 | } 25 | 26 | onBackButtonClick() { 27 | this.location.back(); 28 | } 29 | 30 | onSaveButtonClick() { 31 | this.save.next(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/app/core/components/base-section/base-section.component.css: -------------------------------------------------------------------------------- 1 | .title { 2 | margin-right: 12px; 3 | } -------------------------------------------------------------------------------- /src/app/core/components/base-section/base-section.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ vm.title | async }} 4 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 |
17 | 18 | {{ vm.getColumnCaption(column) | async }} 19 | 20 | 21 | {{(element[column] || '').toString() | translate }} 22 | {{element[column] | date:'dd.MM.yyyy'}} 23 | 24 | 25 |
26 | 27 | 28 | 29 | {{ 'common.caption.actions' | translate }} 30 | 31 | 34 | 35 | 39 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 |
52 |
53 | 54 | -------------------------------------------------------------------------------- /src/app/core/components/base-section/base-section.component.ts: -------------------------------------------------------------------------------- 1 | import { BaseSectionViewModel } from '../../view-models/base-section-view-model.service'; 2 | import { Component, OnInit, ViewChild } from '@angular/core'; 3 | import { MatSort } from '@angular/material'; 4 | 5 | @Component({ 6 | selector: 'app-base-section', 7 | templateUrl: './base-section.component.html', 8 | styleUrls: ['./base-section.component.css'] 9 | }) 10 | export class BaseSectionComponent implements OnInit { 11 | 12 | @ViewChild(MatSort, { static: true }) sort: MatSort; 13 | 14 | constructor( 15 | public vm: BaseSectionViewModel 16 | ) { } 17 | 18 | ngOnInit() { 19 | this.vm.init(); 20 | this.vm.sort = this.sort; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/app/core/components/drop-down-control/drop-down-control.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/core/components/drop-down-control/drop-down-control.component.css -------------------------------------------------------------------------------- /src/app/core/components/drop-down-control/drop-down-control.component.html: -------------------------------------------------------------------------------- 1 | 2 | {{entitySchemaColumn?.caption | translate}} 3 | 4 | 5 | {{enum.name | translate}} 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/app/core/components/drop-down-control/drop-down-control.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, forwardRef, Input } from '@angular/core'; 2 | import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; 3 | 4 | import { ModelDescriptor } from '../../decorators/model.decorator'; 5 | import { ModelPropertyDescriptor, DropDownConfig, DataValueType } from '../../decorators/property.decorator'; 6 | import { BasePageViewModel } from '../../view-models/base-page-view-model.service'; 7 | import { EntitySchemaManagerService } from '../../services/entity-schema-namager.service'; 8 | 9 | @Component({ 10 | selector: 'app-drop-down-control', 11 | templateUrl: './drop-down-control.component.html', 12 | styleUrls: ['./drop-down-control.component.css'], 13 | providers: [ 14 | { 15 | provide: NG_VALUE_ACCESSOR, 16 | useExisting: forwardRef(() => DropDownControlComponent), 17 | multi: true 18 | } 19 | ], 20 | }) 21 | export class DropDownControlComponent implements OnInit, ControlValueAccessor { 22 | 23 | @Input() propertyName: string; 24 | value: any; 25 | disabled: boolean; 26 | enums: Array<{ name: string, value: string }>; 27 | onChange: (value: any) => void; 28 | onTouched: () => void; 29 | 30 | get entitySchema(): ModelDescriptor { 31 | return this.vm.getEntitySchema(); 32 | } 33 | 34 | get entitySchemaColumn(): ModelPropertyDescriptor { 35 | const property = this.entitySchema.getPropertyDescriptor(this.propertyName); 36 | return property; 37 | } 38 | 39 | get dropDownConfig(): DropDownConfig { 40 | const property = this.entitySchemaColumn; 41 | let config = null; 42 | if (property && property.dataValueType === DataValueType.DropDown) { 43 | config = property.dataValueTypeConfig as DropDownConfig; 44 | } 45 | return config; 46 | } 47 | 48 | get selected(): any { 49 | return this.value; 50 | } 51 | set selected(value: any) { 52 | this.setValue(value); 53 | } 54 | 55 | constructor( 56 | public vm: BasePageViewModel 57 | ) { } 58 | 59 | ngOnInit() { 60 | this.enums = this.getEnums(); 61 | } 62 | 63 | writeValue(obj: any): void { 64 | this.value = obj; 65 | } 66 | registerOnChange(fn: any): void { 67 | this.onChange = fn; 68 | } 69 | registerOnTouched(fn: any): void { 70 | this.onTouched = fn; 71 | } 72 | setDisabledState?(isDisabled: boolean): void { 73 | this.disabled = isDisabled; 74 | } 75 | 76 | setValue(value: any) { 77 | this.value = value; 78 | this.onChange(value); 79 | } 80 | 81 | onFocus() { 82 | this.onTouched(); 83 | } 84 | 85 | private getEnums(): Array<{ name: string, value: string }> { 86 | const result = []; 87 | const config = this.dropDownConfig; 88 | if (config && config.refModel) { 89 | const translatePath = config.translatePath || `${this.entitySchema.collectionName}.enums.${this.propertyName}`; 90 | Object.keys(config.refModel) 91 | .filter(key => !isNaN(+key)) 92 | .forEach(key => { 93 | const name = `${translatePath}.${key}`; 94 | const value = +key; 95 | result.push({ name, value }); 96 | }); 97 | } 98 | return result; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/app/core/components/lookup-control/lookup-control.component.css: -------------------------------------------------------------------------------- 1 | app-lookup-control { 2 | width: 100% 3 | } -------------------------------------------------------------------------------- /src/app/core/components/lookup-control/lookup-control.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/app/core/components/lookup-control/lookup-control.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, forwardRef, Input } from '@angular/core'; 2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; 3 | import { BasePageViewModel } from '../../view-models/base-page-view-model.service'; 4 | import { ModelDescriptor } from '../../decorators/model.decorator'; 5 | import { DataValueType, LookupConfig, ModelPropertyDescriptor } from '../../decorators/property.decorator'; 6 | import { EntitySchemaManagerService } from '../../services/entity-schema-namager.service'; 7 | import { BaseModel } from '../../models/base.model'; 8 | 9 | @Component({ 10 | selector: 'app-lookup-control', 11 | templateUrl: './lookup-control.component.html', 12 | styleUrls: ['./lookup-control.component.css'], 13 | providers: [ 14 | { 15 | provide: NG_VALUE_ACCESSOR, 16 | useExisting: forwardRef(() => LookupControlComponent), 17 | multi: true 18 | } 19 | ], 20 | }) 21 | export class LookupControlComponent implements OnInit, ControlValueAccessor { 22 | 23 | @Input() propertyName: string; 24 | value: any; 25 | disabled: boolean; 26 | onChange: (value: any) => void; 27 | onTouched: () => void; 28 | 29 | get entitySchema(): ModelDescriptor { 30 | return this.vm.getEntitySchema(); 31 | } 32 | 33 | get entitySchemaColumn(): ModelPropertyDescriptor { 34 | const property = this.entitySchema.getPropertyDescriptor(this.propertyName); 35 | return property; 36 | } 37 | 38 | get lookupConfig(): LookupConfig { 39 | const property = this.entitySchemaColumn; 40 | let config = null; 41 | if (property && property.dataValueType === DataValueType.Lookup) { 42 | config = property.dataValueTypeConfig as LookupConfig; 43 | } 44 | return config; 45 | } 46 | 47 | constructor( 48 | public vm: BasePageViewModel, 49 | private esm: EntitySchemaManagerService 50 | ) { } 51 | 52 | ngOnInit() { 53 | } 54 | 55 | writeValue(obj: any): void { 56 | this.value = obj || null; 57 | } 58 | registerOnChange(fn: any): void { 59 | this.onChange = fn; 60 | } 61 | registerOnTouched(fn: any): void { 62 | this.onTouched = fn; 63 | } 64 | setDisabledState?(isDisabled: boolean): void { 65 | this.disabled = isDisabled; 66 | } 67 | 68 | setValue(value: any) { 69 | this.value = value; 70 | this.onChange(value); 71 | } 72 | 73 | onFocus() { 74 | this.onTouched(); 75 | } 76 | 77 | openLookup() { 78 | const config = this.lookupConfig; 79 | if (config) { 80 | const schemaName = this.esm.getSchemaName(config.refModel as any); 81 | const entity = this.esm.createEntity(schemaName); 82 | const refSchema = this.esm.getEntitySchemaByName(schemaName); 83 | let displayColumnNames = refSchema.displayPropertyName ? [refSchema.displayPropertyName] : []; 84 | displayColumnNames = [...displayColumnNames, ...(config.displayColumns || []).filter(x => displayColumnNames.indexOf(x) < 0)]; 85 | const displayColumns = displayColumnNames 86 | .map(path => refSchema.getPropertyDescriptor(path)) 87 | .filter(c => !!c) 88 | .map(column => { 89 | return { 90 | path: column.name, 91 | title: column.caption 92 | }; 93 | }); 94 | this.vm.openLookupDialog(entity, displayColumns).subscribe( 95 | result => this.onLookupResult(entity, result, config.columns) 96 | ); 97 | } 98 | } 99 | 100 | onLookupResult(entity: BaseModel, result, columns: string[]) { 101 | const entitySchema = this.entitySchema; 102 | let { primaryPropertyName, displayPropertyName } = entitySchema; 103 | primaryPropertyName = primaryPropertyName || 'id'; 104 | displayPropertyName = displayPropertyName || 'name'; 105 | const values = { 106 | [primaryPropertyName]: result[primaryPropertyName], 107 | [displayPropertyName]: result[displayPropertyName], 108 | }; 109 | if (entitySchema.imagePropertyName) { 110 | values[entitySchema.imagePropertyName] = result[entitySchema.imagePropertyName] 111 | } 112 | if (Array.isArray(columns)) { 113 | columns.forEach(path => values[path] = result[path]); 114 | } 115 | this.esm.setEntityColumnsValues(entity, values); 116 | this.value = entity; 117 | this.onChange(entity); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/app/core/components/lookup-dialog/lookup-data.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { DataService } from '../../data.service'; 3 | 4 | @Injectable() 5 | export class LookupDataService extends DataService { 6 | collectionName = ''; 7 | 8 | setCollectionName(name: string): LookupDataService { 9 | this.collectionName = name; 10 | return this; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/app/core/components/lookup-dialog/lookup-dialog.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/core/components/lookup-dialog/lookup-dialog.component.css -------------------------------------------------------------------------------- /src/app/core/components/lookup-dialog/lookup-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Select {{data.collectionName}}

2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 |
{{ column.title | translate }} {{ element[column.path] }} 12 | 15 |
22 |
23 |
24 | 25 | 26 |
-------------------------------------------------------------------------------- /src/app/core/components/lookup-dialog/lookup-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject } from '@angular/core'; 2 | import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; 3 | import { LookupDataService } from './lookup-data.service'; 4 | import { take } from 'rxjs/operators'; 5 | 6 | export interface DialogData { 7 | collectionName: string; 8 | displayedColumns: Array<{path: string; title: string}>; 9 | filters?: any; 10 | result?: any; 11 | } 12 | 13 | @Component({ 14 | selector: 'app-lookup-dialog', 15 | templateUrl: './lookup-dialog.component.html', 16 | styleUrls: ['./lookup-dialog.component.css'], 17 | providers: [ 18 | LookupDataService 19 | ] 20 | }) 21 | export class LookupDialogComponent implements OnInit { 22 | 23 | public itemList: Array; 24 | 25 | get displayedColumns(): Array { 26 | const res = [ ...this.data.displayedColumns.map(c => c.path), 'menu']; 27 | return res; 28 | } 29 | 30 | constructor( 31 | public dialogRef: MatDialogRef, 32 | private lookupDataService: LookupDataService, 33 | @Inject(MAT_DIALOG_DATA) public data: DialogData 34 | ) { 35 | lookupDataService.setCollectionName(data.collectionName); 36 | } 37 | 38 | ngOnInit() { 39 | this.lookupDataService.getAll().pipe(take(1)).subscribe( 40 | data => this.itemList = data 41 | ); 42 | } 43 | 44 | onCancelClick(): void { 45 | this.dialogRef.close(); 46 | } 47 | 48 | onSubmit(result) { 49 | this.data.result = result; 50 | this.dialogRef.close(result); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/app/core/core.module.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { NgModule } from '@angular/core'; 3 | import { CommonModule } from '@angular/common'; 4 | import { HttpClientModule, HttpClient } from '@angular/common/http'; 5 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 6 | 7 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 8 | 9 | 10 | import { 11 | MatButtonModule, 12 | MatSnackBarModule, 13 | MatSidenavModule, 14 | MatIconModule, 15 | MatToolbarModule, 16 | MatMenuModule, 17 | MatListModule, 18 | MatTableModule, 19 | MatCardModule, 20 | MatFormFieldModule, 21 | MatInputModule, 22 | MatGridListModule, 23 | MatSelectModule, 24 | MatDialogModule, 25 | MatExpansionModule, 26 | MatProgressSpinnerModule, 27 | MatSortModule, 28 | } from '@angular/material'; 29 | import { BaseSectionComponent } from './components/base-section/base-section.component'; 30 | import { BasePageComponent } from './components/base-page/base-page.component'; 31 | import { AppTranslateService } from '../app-translate.service'; 32 | import { LookupDialogComponent } from './components/lookup-dialog/lookup-dialog.component'; 33 | 34 | import { environment } from '../../environments/environment'; 35 | import { BaseDetailComponent } from './components/base-detail/base-detail.component'; 36 | import { LookupControlComponent } from './components/lookup-control/lookup-control.component'; 37 | import { DropDownControlComponent } from './components/drop-down-control/drop-down-control.component'; 38 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 39 | 40 | export function HttpLoaderFactory(http: HttpClient) { 41 | return new TranslateHttpLoader(http, 'assets/i18n/'); 42 | } 43 | 44 | @NgModule({ 45 | imports: [ 46 | CommonModule, 47 | FormsModule, 48 | ReactiveFormsModule, 49 | HttpClientModule, 50 | 51 | MatButtonModule, 52 | MatSnackBarModule, 53 | MatProgressSpinnerModule, 54 | MatSidenavModule, 55 | MatIconModule, 56 | MatToolbarModule, 57 | MatMenuModule, 58 | MatListModule, 59 | MatTableModule, 60 | MatCardModule, 61 | MatFormFieldModule, 62 | MatInputModule, 63 | MatGridListModule, 64 | MatSelectModule, 65 | MatDialogModule, 66 | MatExpansionModule, 67 | MatSortModule, 68 | 69 | TranslateModule.forRoot(), 70 | ], 71 | exports: [ 72 | CommonModule, 73 | FormsModule, 74 | ReactiveFormsModule, 75 | TranslateModule, 76 | 77 | MatButtonModule, 78 | MatSnackBarModule, 79 | MatProgressSpinnerModule, 80 | MatSidenavModule, 81 | MatIconModule, 82 | MatToolbarModule, 83 | MatMenuModule, 84 | MatListModule, 85 | MatTableModule, 86 | MatCardModule, 87 | MatFormFieldModule, 88 | MatInputModule, 89 | MatGridListModule, 90 | MatSelectModule, 91 | MatDialogModule, 92 | MatExpansionModule, 93 | MatSortModule, 94 | 95 | BaseSectionComponent, 96 | BasePageComponent, 97 | LookupDialogComponent, 98 | BaseDetailComponent, 99 | LookupControlComponent, 100 | DropDownControlComponent, 101 | ], 102 | declarations: [ 103 | BaseSectionComponent, 104 | BasePageComponent, 105 | LookupDialogComponent, 106 | BaseDetailComponent, 107 | LookupControlComponent, 108 | DropDownControlComponent, 109 | ], 110 | entryComponents: [LookupDialogComponent], 111 | providers: [ 112 | { provide: TranslateService, useClass: AppTranslateService } 113 | ] 114 | }) 115 | export class CoreModule { } 116 | -------------------------------------------------------------------------------- /src/app/core/data.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Observable, of as observableOf, from } from 'rxjs'; 3 | import { map, tap } from 'rxjs/operators'; 4 | 5 | import { BaseModel } from './models/base.model'; 6 | import { Guid } from 'guid-typescript'; 7 | import { FirebaseService } from './firebase/firebase.service'; 8 | 9 | @Injectable() 10 | export abstract class DataService extends FirebaseService { 11 | 12 | abstract collectionName: string; 13 | 14 | getAll(): Observable> { 15 | return super.getAll(); 16 | } 17 | 18 | getById(id: string): Observable { 19 | return super.getById(id); 20 | } 21 | 22 | create(dto: any): Observable { 23 | dto = this.prepareDto(dto); 24 | if (!dto.id) { 25 | dto.id = Guid.create().toString(); 26 | } 27 | return super.create(dto); 28 | } 29 | 30 | update(id: string, dto: T): Observable { 31 | dto = this.prepareDto(dto); 32 | return super.update(id, dto); 33 | } 34 | 35 | remove(id: string): Observable { 36 | return super.remove(id); 37 | } 38 | 39 | protected prepareDto(dto): any { 40 | if (dto) { 41 | Object.keys(dto).forEach(key => { 42 | let value = dto[key]; 43 | if (value === undefined) { 44 | value = null; 45 | } 46 | if (typeof value === 'object' && value instanceof BaseModel) { 47 | value = Object.assign({}, value); 48 | value = this.prepareDto(value); 49 | } 50 | if (Array.isArray(value)) { 51 | value = value.map(v => this.prepareDto(v)); 52 | } 53 | if (!value && key === 'id') { 54 | value = Guid.create().toString(); 55 | } 56 | dto[key] = value; 57 | }); 58 | } 59 | dto = Object.assign({}, dto); 60 | return dto; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/app/core/decorators/enum.decorator.ts: -------------------------------------------------------------------------------- 1 | export class EnumDescriptor { 2 | name: string; 3 | translatePath: string; 4 | type?: 'number' | 'string' = 'number'; 5 | } 6 | 7 | export function Enum(descriptor: EnumDescriptor) { 8 | descriptor = Object.assign(new EnumDescriptor(), descriptor); 9 | return target => { 10 | let enums = Reflect.getMetadata('enums', Object.prototype) as Array; 11 | if (!enums) { 12 | enums = []; 13 | Reflect.defineMetadata('enums', enums, Object.prototype); 14 | } 15 | if (!enums.includes(x => x.name === descriptor.name)) { 16 | enums.push({ 17 | name: descriptor.name, 18 | ctor: target, 19 | descriptor 20 | }); 21 | } 22 | target.getMetaData = () => descriptor; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/app/core/decorators/method.decorator.ts: -------------------------------------------------------------------------------- 1 | export enum ModelMethodType { 2 | Action 3 | } 4 | 5 | export class ModelMethodAction { 6 | caption: string; 7 | icon?: string; 8 | visible?: () => boolean; 9 | enabled?: () => boolean; 10 | } 11 | 12 | export class ModelMethodDescriptor { 13 | type?: ModelMethodType = ModelMethodType.Action; 14 | name?: string; 15 | config?: ModelMethodAction; 16 | } 17 | 18 | export function ModelMethod(options: ModelMethodDescriptor): MethodDecorator { 19 | return (target, propertyKey, descriptor) => { 20 | let modelMethods = Reflect.getMetadata('modelMethods', target.constructor) as Array; 21 | if (!modelMethods) { 22 | modelMethods = []; 23 | Reflect.defineMetadata('modelMethods', modelMethods, target.constructor); 24 | } 25 | if (!modelMethods.includes(propertyKey)) { 26 | modelMethods.push(propertyKey); 27 | } 28 | const opts = Object.assign(new ModelMethodDescriptor(), { name: propertyKey.toString() }, options); 29 | Reflect.defineMetadata(`model_method_${propertyKey.toString()}`, opts, target.constructor); 30 | }; 31 | } 32 | 33 | ModelMethod.getDescriptor = (methodKey: string | symbol, target): ModelMethodDescriptor => { 34 | return Reflect.getMetadata(`model_method_${methodKey.toString()}`, target); 35 | }; 36 | -------------------------------------------------------------------------------- /src/app/core/decorators/model.decorator.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable: ban-types 2 | import { ModelPropertyDescriptor, ModelProperty } from './property.decorator'; 3 | import { ModelMethod, ModelMethodDescriptor } from './method.decorator'; 4 | 5 | export class ModelDescriptor { 6 | name: string; 7 | caption: string; 8 | collectionName: string; 9 | primaryPropertyName ? = 'id'; 10 | displayPropertyName ? = 'name'; 11 | imagePropertyName ? = 'image'; 12 | getPropertyDescriptor?: (name) => ModelPropertyDescriptor; 13 | getMethodDescriptor?: (name) => ModelMethodDescriptor; 14 | getMethods?: () => Array; 15 | getProperties?: () => Array; 16 | } 17 | 18 | export class SchemaDescriptor { 19 | name: string; 20 | ctor: Function; 21 | descriptor: ModelDescriptor; 22 | } 23 | 24 | export function Model(descriptor: ModelDescriptor): ClassDecorator { 25 | descriptor = Object.assign(new ModelDescriptor(), descriptor); 26 | return target => { 27 | let models = Reflect.getMetadata('models', Object.prototype) as Array; 28 | if (!models) { 29 | models = []; 30 | Reflect.defineMetadata('models', models, Object.prototype); 31 | } 32 | if (!models.includes(x => x.name === descriptor.name)) { 33 | models.push({ 34 | name: descriptor.name, 35 | ctor: target, 36 | descriptor 37 | }); 38 | } 39 | Reflect.defineMetadata('model', descriptor, target); 40 | }; 41 | } 42 | 43 | Model.getModelProperties = (target: Function): Array => { 44 | return Reflect.getMetadata('modelProperties', target) as Array; 45 | }; 46 | 47 | Model.getModelMethods = (target: Function): Array => { 48 | return Reflect.getMetadata('modelMethods', target) as Array; 49 | }; 50 | 51 | Model.getDescriptor = (target: Function): ModelDescriptor => { 52 | return Reflect.getMetadata('model', target); 53 | }; 54 | 55 | Model.getModelDescriptor = (name: string): ModelDescriptor => { 56 | const metaData = Reflect.getMetadata('models', Object.prototype) as Array; 57 | const schema = metaData.find(x => x.name === name); 58 | return { 59 | ... schema.descriptor, 60 | getPropertyDescriptor: (propertyName: string): ModelPropertyDescriptor => ModelProperty.getDescriptor(propertyName, schema.ctor), 61 | getMethodDescriptor: (methodName: string): ModelMethodDescriptor => ModelMethod.getDescriptor(methodName, schema.ctor), 62 | getProperties: (): Array => Model.getModelProperties(schema.ctor) 63 | .map( 64 | (propertyName: string) => ModelProperty.getDescriptor(propertyName, schema.ctor) 65 | ), 66 | getMethods: (): Array => Model.getModelMethods(schema.ctor) 67 | .map( 68 | (propertyName: string) => ModelMethod.getDescriptor(propertyName, schema.ctor) 69 | ), 70 | }; 71 | }; 72 | -------------------------------------------------------------------------------- /src/app/core/decorators/property.decorator.ts: -------------------------------------------------------------------------------- 1 | 2 | import { ValidatorFn } from '@angular/forms'; 3 | 4 | // #region Configs 5 | export enum DataValueType { 6 | Text = 'text', 7 | RichText = 'richText', 8 | Decimal = 'number', 9 | Integer = 'integer', 10 | Money = 'money', 11 | Date = 'date', 12 | Lookup = 'lookup', 13 | DropDown = 'dropDown', 14 | Boolean = 'boolean', 15 | Image = 'image', 16 | Array = 'array', 17 | Custom = 'custom' 18 | } 19 | 20 | export class DropDownConfig { 21 | // tslint:disable-next-line:ban-types 22 | refModel: Function | Object; 23 | filters?: any; 24 | columns?: Array; 25 | translatePath?: string; 26 | } 27 | 28 | export class LookupConfig extends DropDownConfig { 29 | displayColumns?: Array; 30 | } 31 | 32 | export abstract class NumberConfig { 33 | min?: number; 34 | max?: number; 35 | unsigned?: boolean; 36 | } 37 | 38 | export class IntegerConfig extends NumberConfig {} 39 | 40 | export class DecimalConfig extends NumberConfig {} 41 | 42 | export class DateConfig {} 43 | 44 | export class ModelPropertyDescriptor { 45 | name?: string; 46 | caption: string; 47 | dataValueType: DataValueType = DataValueType.Text; 48 | dataValueTypeConfig?: LookupConfig | DropDownConfig | DecimalConfig | IntegerConfig | DateConfig; 49 | required?: boolean; 50 | readOnly?: boolean; 51 | hidden?: boolean; 52 | validators?: Array; 53 | defaultValue?: any; 54 | dataLocalizationPath?: string; 55 | } 56 | // #endregion 57 | 58 | export function ModelProperty(descriptor: ModelPropertyDescriptor): PropertyDecorator { 59 | descriptor = Object.assign(new ModelPropertyDescriptor(), descriptor); 60 | return (target, propertyKey) => { 61 | let modelProperties = Reflect.getMetadata('modelProperties', target.constructor) as Array; 62 | if (!modelProperties) { 63 | modelProperties = []; 64 | Reflect.defineMetadata('modelProperties', modelProperties, target.constructor); 65 | } 66 | if (!modelProperties.includes(propertyKey)) { 67 | modelProperties.push(propertyKey); 68 | } 69 | Reflect.defineMetadata(`model_property_${propertyKey.toString()}`, { ...descriptor, name: propertyKey }, target.constructor); 70 | }; 71 | } 72 | 73 | ModelProperty.getDescriptor = (propertyKey: string | symbol, target): ModelPropertyDescriptor => { 74 | return Reflect.getMetadata(`model_property_${propertyKey.toString()}`, target); 75 | }; 76 | -------------------------------------------------------------------------------- /src/app/core/decorators/view-model-action.decorator.ts: -------------------------------------------------------------------------------- 1 | export class ViewModelActionDescriptor { 2 | name?: string; 3 | caption: string; 4 | icon?: string; 5 | visible?: () => boolean; 6 | enabled?: () => boolean; 7 | } 8 | 9 | export function ViewModelAction(options: ViewModelActionDescriptor): MethodDecorator { 10 | return (target, propertyKey, descriptor) => { 11 | let viewModelActions = Reflect.getMetadata('viewModelActions', target) as Array; 12 | if (!viewModelActions) { 13 | viewModelActions = []; 14 | Reflect.defineMetadata('viewModelActions', viewModelActions, target); 15 | } 16 | if (!viewModelActions.includes(propertyKey)) { 17 | viewModelActions.push(propertyKey); 18 | } 19 | const opts = Object.assign(new ViewModelActionDescriptor(), { name: propertyKey.toString() }, options); 20 | Reflect.defineMetadata(`model_method_${propertyKey.toString()}`, opts, target); 21 | }; 22 | } 23 | 24 | ViewModelAction.getDescriptor = (actionName: string | symbol, target): ViewModelActionDescriptor => { 25 | return Reflect.getMetadata(`model_method_${actionName.toString()}`, target); 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /src/app/core/firebase/firebase.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule, InjectionToken } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import 'firebase/app'; 4 | import 'firebase/auth'; 5 | import 'firebase/database'; 6 | 7 | declare const firebase: any; 8 | 9 | const firebaseDefaultApp = firebase.app(); 10 | 11 | export const FIRESTORE_INJECTION_TOKEN = new InjectionToken('firestore', { 12 | providedIn: 'root', 13 | factory: () => firebaseDefaultApp.firestore() 14 | }); 15 | 16 | @NgModule({ 17 | declarations: [], 18 | imports: [ 19 | CommonModule, 20 | ] 21 | }) 22 | export class FirebaseModule {} 23 | -------------------------------------------------------------------------------- /src/app/core/firebase/firebase.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | 3 | import { Observable, from } from 'rxjs'; 4 | import { map, mergeMap } from 'rxjs/operators'; 5 | 6 | import { Guid } from 'guid-typescript'; 7 | import { FIRESTORE_INJECTION_TOKEN } from './firebase.module'; 8 | 9 | declare const firebase: any; 10 | @Injectable() 11 | export abstract class FirebaseService { 12 | 13 | protected abstract collectionName: string; 14 | protected get collection(): firebase.firestore.CollectionReference { 15 | return this.db.collection(this.collectionName); 16 | } 17 | 18 | constructor(@Inject(FIRESTORE_INJECTION_TOKEN) protected db: firebase.firestore.Firestore) { } 19 | 20 | public getAll(): Observable { 21 | const query = this.getAllQuery() 22 | .pipe( 23 | map(r => r.docs.map(d => ({ 24 | id: d.id, 25 | ...d.data() 26 | } as unknown as T))) 27 | ); 28 | return query; 29 | } 30 | 31 | public getById(id: string): Observable { 32 | const query = from(this.collection.doc(id).get()) 33 | .pipe( 34 | map(d => ({ 35 | id: d.id, 36 | ...d.data() 37 | } as unknown as T)) 38 | ); 39 | return query; 40 | } 41 | 42 | public create(dto: T): Observable { 43 | const id = Guid.create().toString(); 44 | const docRef = this.collection.doc(id); 45 | const query = from(docRef.set(dto)) 46 | .pipe( 47 | mergeMap(_ => docRef.get()), 48 | map(d => ({ 49 | id: d.id, 50 | ...d.data() 51 | } as unknown as T)) 52 | ); 53 | return query; 54 | } 55 | 56 | public update(id: string, dto: T): Observable { 57 | const docRef = this.collection.doc(id); 58 | const query = from(docRef.set(dto)).pipe( 59 | mergeMap(_ => docRef.get()), 60 | map(d => ({ 61 | id: d.id, 62 | ...d.data() 63 | } as unknown as T)) 64 | ); 65 | return query; 66 | } 67 | 68 | public remove(id: string): Observable { 69 | const docRef = this.collection.doc(id); 70 | const query = docRef.delete(); 71 | return from(query); 72 | } 73 | 74 | protected getAllQuery(): Observable { 75 | return from(this.collection.get()); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/app/core/models/base.model.ts: -------------------------------------------------------------------------------- 1 | import { Guid } from 'guid-typescript'; 2 | import { ModelProperty, ModelPropertyDescriptor } from '../decorators/property.decorator'; 3 | import { Model, ModelDescriptor } from '../decorators/model.decorator'; 4 | 5 | export class BaseModel { 6 | 7 | id: string; 8 | 9 | static toString(): string { 10 | return 'BaseModel'; 11 | } 12 | 13 | 14 | toString(): string { 15 | const displayColumnName = this.getDisplayColumnName(); 16 | const stringValue = this[displayColumnName]; 17 | return stringValue || ''; 18 | } 19 | 20 | getModelDescriptor(): ModelDescriptor { 21 | return Model.getDescriptor(this.constructor); 22 | } 23 | 24 | getModelProperties(): Array { 25 | return Model.getModelProperties(this.constructor); 26 | } 27 | 28 | getPropertyDescriptor(propertyKey: string | symbol): ModelPropertyDescriptor { 29 | return ModelProperty.getDescriptor(propertyKey, this.constructor); 30 | } 31 | 32 | getPrimaryColumnName(): string { 33 | const metaData = this.getModelDescriptor(); 34 | return metaData && metaData.primaryPropertyName; 35 | } 36 | 37 | getDisplayColumnName(): string { 38 | const metaData = this.getModelDescriptor(); 39 | return metaData && metaData.displayPropertyName; 40 | } 41 | 42 | getImageColumnName(): string { 43 | const metaData = this.getModelDescriptor(); 44 | return metaData && metaData.imagePropertyName; 45 | } 46 | 47 | getCollectionName(): string { 48 | const metaData = this.getModelDescriptor(); 49 | return metaData && metaData.collectionName; 50 | } 51 | 52 | getCaption(): string { 53 | const metaData = this.getModelDescriptor(); 54 | return metaData && metaData.caption; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/app/core/services/entity-schema-namager.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ViewModelActionDescriptor, ViewModelAction } from '../decorators/view-model-action.decorator'; 3 | import { BaseViewModel } from '../view-models/base-view-model.service'; 4 | import { Model, ModelDescriptor } from '../decorators/model.decorator'; 5 | import { BaseModel } from '../models/base.model'; 6 | import { DataValueType, LookupConfig, DropDownConfig } from '../decorators/property.decorator'; 7 | 8 | // tslint:disable: ban-types 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class EntitySchemaManagerService { 13 | 14 | constructor() { } 15 | 16 | public getActions(target: BaseViewModel): Array { 17 | const actions = Reflect.getMetadata('viewModelActions', target) as Array; 18 | const result: Array = Array.isArray(actions) 19 | ? actions.map(name => ViewModelAction.getDescriptor(name, target)) 20 | : null; 21 | return result; 22 | } 23 | 24 | public getEntitySchemaByName(entitySchemaName: string): ModelDescriptor { 25 | return Model.getModelDescriptor(entitySchemaName); 26 | } 27 | 28 | public createEntity(entitySchemaName: string): BaseModel { 29 | const models = Reflect.getMetadata('models', Object.prototype) as Array; 30 | const model = models.find(x => x.name === entitySchemaName); 31 | const entity = Object.create(model.ctor.prototype); 32 | return entity as BaseModel; 33 | } 34 | 35 | public getSchemaName(schema: Function): string { 36 | return Reflect.getMetadata('model', schema).name; 37 | } 38 | 39 | public setEntityColumnsValues(entity: BaseModel, values) { 40 | if (!entity || !values) { 41 | return; 42 | } 43 | const columnNames = Object.keys(values); 44 | columnNames.forEach(key => { 45 | const value = values[key]; 46 | this.setEntityColumnValue(entity, key, value); 47 | }); 48 | } 49 | 50 | // TODO: refactoring 51 | public setEntityColumnValue(entity: BaseModel, key: string, value) { 52 | if (value && value.toDate && value.toDate.constructor === Function) { 53 | value = value.toDate(); 54 | } 55 | const propertyMetaData = entity.getPropertyDescriptor(key); 56 | if (propertyMetaData) { 57 | const valueType = propertyMetaData.dataValueType; 58 | switch (valueType) { 59 | case DataValueType.Lookup: { 60 | const lookupConfig = propertyMetaData.dataValueTypeConfig as LookupConfig; 61 | const refSchema = lookupConfig && lookupConfig.refModel as Function; 62 | const refSchemaName = refSchema && this.getSchemaName(refSchema); 63 | if (refSchemaName && typeof value === 'object') { 64 | const refEntity = this.createEntity(refSchemaName); 65 | this.setEntityColumnsValues(refEntity, value); 66 | value = refEntity; 67 | } 68 | break; 69 | } 70 | case DataValueType.DropDown: { 71 | /*const dropDownConfig = propertyMetaData.dataValueTypeConfig as DropDownConfig; 72 | const refSchema = dropDownConfig && dropDownConfig.refModel as any; 73 | if (refSchema && refSchema.getMetaData) { 74 | const enumMetaData = refSchema.getMetaData() as EnumDescriptor; 75 | value = `${enumMetaData.translatePath}.${value}`; 76 | }*/ 77 | break; 78 | } 79 | case DataValueType.Array: { 80 | // TODO: map each element ot create inner entity; 81 | value = (Array.isArray(value) ? value : []) as Array; 82 | const dropDownConfig = propertyMetaData.dataValueTypeConfig as DropDownConfig; 83 | const refSchema = dropDownConfig && dropDownConfig.refModel as Function; 84 | 85 | value = value.map(v => { 86 | const e = this.createEntity(this.getSchemaName(refSchema)); 87 | this.setEntityColumnsValues(e, v); 88 | return e; 89 | }); 90 | break; 91 | } 92 | } 93 | entity[key] = value; 94 | } 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/app/core/translate.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { TranslateService } from '@ngx-translate/core'; 3 | 4 | @Injectable({ providedIn: 'root' }) 5 | export class CoreTranslateService extends TranslateService { } 6 | -------------------------------------------------------------------------------- /src/app/core/view-models/base-detail-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { FormArray, AbstractControl } from '@angular/forms'; 2 | import { LookupConfig } from '../decorators/property.decorator'; 3 | import { BasePageViewModel } from './base-page-view-model.service'; 4 | import { Observable } from 'rxjs'; 5 | 6 | export abstract class BaseDetailViewModelService extends BasePageViewModel { 7 | formArray: FormArray; 8 | 9 | abstract visibleFields: Array; 10 | 11 | get subTitle$(): Observable { 12 | return this.translate && this.translate.get(this.entitySchema.caption); 13 | } 14 | 15 | get controlList(): Array { 16 | return this.formArray && this.formArray.controls; 17 | } 18 | 19 | add() { 20 | const schema = this.entitySchema; 21 | const properties = schema.getProperties().map(x => x.name); 22 | this.controlList.push( 23 | this.createForm(properties, schema) 24 | ); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/app/core/view-models/base-section-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { BaseViewModel } from './base-view-model.service'; 2 | import { MatTableDataSource, MatSort } from '@angular/material'; 3 | import { BaseModel } from '../models/base.model'; 4 | import { Observable } from 'rxjs'; 5 | import { map } from 'rxjs/operators'; 6 | 7 | export abstract class BaseSectionViewModel extends BaseViewModel { 8 | 9 | dataSource: MatTableDataSource; 10 | saveButtonHidden: boolean; 11 | displayedColumns: Array; 12 | sort: MatSort; 13 | 14 | get columnsToDisplay(): Array { 15 | // tslint:disable-next-line:no-non-null-assertion 16 | return this.displayedColumns!.filter(x => x !== 'menu'); 17 | } 18 | 19 | get title(): Observable { 20 | const caption = this.entitySchema && this.entitySchema.caption; 21 | return caption && this.translate && this.translate.get(caption); 22 | } 23 | 24 | 25 | init() { 26 | super.init(); 27 | this.loadData(); 28 | } 29 | 30 | loadData() { 31 | this.dataService.getAll() 32 | .pipe( 33 | map( 34 | data => Array.isArray(data) && data.map(x => { 35 | const entity = this.createEntity(this.entitySchemaName); 36 | this.setEntityColumnsValues(entity, x); 37 | return entity; 38 | }) 39 | ) 40 | ) 41 | .subscribe(data => { 42 | this.dataSource = new MatTableDataSource(data); 43 | this.dataSource.sort = this.sort; 44 | }); 45 | } 46 | 47 | onNewButtonClick() { 48 | this.router.navigate(['new'], { relativeTo: this.route }); 49 | } 50 | 51 | edit(element: BaseModel) { 52 | this.router.navigate(['edit', element.id], { relativeTo: this.route }); 53 | } 54 | 55 | remove(element: BaseModel) { 56 | this.dataService.remove(element.id).subscribe(() => null); 57 | } 58 | 59 | getColumnCaption(columnName: string): Observable { 60 | const column = this.entitySchema && this.entitySchema.getPropertyDescriptor(columnName); 61 | return column ? this.translate.get(column.caption) : null; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/app/core/view-models/base-view-model.service.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable:ban-types 2 | import { MatSnackBar } from '@angular/material'; 3 | import { Injector } from '@angular/core'; 4 | import { BaseModel } from '../models/base.model'; 5 | import { DataValueType, LookupConfig, DropDownConfig, ModelPropertyDescriptor } from '../decorators/property.decorator'; 6 | import { DataService } from '../data.service'; 7 | import { TranslateService } from '@ngx-translate/core'; 8 | import { FormBuilder } from '@angular/forms'; 9 | import { ActivatedRoute, Router } from '@angular/router'; 10 | import { MatDialog } from '@angular/material'; 11 | import { Location } from '@angular/common'; 12 | import { Model, ModelDescriptor } from '../decorators/model.decorator'; 13 | import { ViewModelActionDescriptor, ViewModelAction } from '../decorators/view-model-action.decorator'; 14 | import { EntitySchemaManagerService } from '../services/entity-schema-namager.service'; 15 | 16 | export abstract class BaseViewModel { 17 | 18 | protected dataService: DataService; 19 | protected mobileQuery: MediaQueryList; 20 | protected translate: TranslateService; 21 | protected formBuilder: FormBuilder; 22 | protected route: ActivatedRoute; 23 | protected router: Router; 24 | protected location: Location; 25 | protected dialog: MatDialog; 26 | protected snackBar: MatSnackBar; 27 | 28 | protected entity: BaseModel; 29 | protected entitySchemaName: string; 30 | protected entitySchema: ModelDescriptor; 31 | protected esm: EntitySchemaManagerService; 32 | 33 | get actions(): Array { 34 | const result = this.esm.getActions(this); 35 | return result; 36 | } 37 | 38 | constructor( 39 | protected injector: Injector 40 | ) { 41 | this.setUpDeps(); 42 | } 43 | 44 | init() { 45 | this.entitySchema = Model.getModelDescriptor(this.entitySchemaName); 46 | } 47 | 48 | isDate(value): boolean { 49 | return value && value.constructor === Date; 50 | } 51 | 52 | getEntitySchemaByName(entitySchemaName: string): ModelDescriptor { 53 | const result = this.esm.getEntitySchemaByName(entitySchemaName) 54 | return result; 55 | } 56 | 57 | getEntitySchemaPropertyByName(propertyName: string): ModelPropertyDescriptor { 58 | return this.entitySchema.getPropertyDescriptor(propertyName); 59 | } 60 | 61 | invokeAction(action: ViewModelActionDescriptor) { 62 | if (this[action.name]) { 63 | this[action.name](); 64 | } 65 | } 66 | 67 | getEntitySchema(): ModelDescriptor { 68 | return this.entitySchema; 69 | } 70 | 71 | protected setUpDeps() { 72 | this.esm = this.injector.get(EntitySchemaManagerService); 73 | this.dataService = this.injector.get(DataService); 74 | this.translate = this.injector.get(TranslateService); 75 | this.formBuilder = this.injector.get(FormBuilder); 76 | this.route = this.injector.get(ActivatedRoute); 77 | this.router = this.injector.get(Router); 78 | this.location = this.injector.get(Location); 79 | this.dialog = this.injector.get(MatDialog); 80 | this.snackBar = this.injector.get(MatSnackBar); 81 | } 82 | 83 | protected createEntity(entitySchemaName: string): BaseModel { 84 | const entity = this.esm.createEntity(entitySchemaName); 85 | return entity; 86 | } 87 | 88 | protected setEntityColumnsValues(entity: BaseModel, values) { 89 | this.esm.setEntityColumnsValues(entity, values); 90 | } 91 | 92 | protected setEntityColumnValue(entity: BaseModel, key: string, value) { 93 | this.esm.setEntityColumnValue(entity, key, value); 94 | } 95 | 96 | protected getSchemaName(schema: Function): string { 97 | return this.esm.getSchemaName(schema); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/app/customers/components/customer-list/customer-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/customers/components/customer-list/customer-list.component.css -------------------------------------------------------------------------------- /src/app/customers/components/customer-list/customer-list.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/customers/components/customer-list/customer-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router, ActivatedRoute } from '@angular/router'; 3 | 4 | import { CustomerService } from '../../services/customer.service'; 5 | import { Customer } from '../../models/customer'; 6 | import { MatTableDataSource } from '@angular/material'; 7 | import { CustomerSectionViewModelService } from '../../services/customer-section-view-model.service'; 8 | import { BaseSectionViewModel } from '../../../core/view-models/base-section-view-model.service'; 9 | import { DataService } from '../../../core/data.service'; 10 | 11 | @Component({ 12 | selector: 'app-customer-list', 13 | templateUrl: './customer-list.component.html', 14 | styleUrls: ['./customer-list.component.css'], 15 | providers: [ 16 | { provide: BaseSectionViewModel, useClass: CustomerSectionViewModelService }, 17 | { provide: DataService, useClass: CustomerService } 18 | ] 19 | }) 20 | export class CustomerListComponent implements OnInit { 21 | 22 | constructor( 23 | ) { } 24 | 25 | ngOnInit() { 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/app/customers/components/customer-page/customer-page.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/customers/components/customer-page/customer-page.component.css -------------------------------------------------------------------------------- /src/app/customers/components/customer-page/customer-page.component.html: -------------------------------------------------------------------------------- 1 | 4 | {{ 'customers.customer-page' | translate }} 5 | {{ vm.subTitle$ | async }} 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 |
-------------------------------------------------------------------------------- /src/app/customers/components/customer-page/customer-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, OnDestroy } from '@angular/core'; 2 | import { CustomerViewModelService } from '../../services/customer-view-model.service'; 3 | import { DataService } from '../../../core/data.service'; 4 | import { CustomerService } from '../../services/customer.service'; 5 | import { BasePageViewModel } from 'src/app/core/view-models/base-page-view-model.service'; 6 | 7 | @Component({ 8 | selector: 'app-customer-page', 9 | templateUrl: './customer-page.component.html', 10 | styleUrls: ['./customer-page.component.css'], 11 | providers: [ 12 | CustomerViewModelService, 13 | { provide: BasePageViewModel, useExisting: CustomerViewModelService }, 14 | { provide: DataService, useExisting: CustomerService } 15 | ] 16 | }) 17 | export class CustomerPageComponent implements OnInit, OnDestroy { 18 | 19 | constructor( 20 | public vm: CustomerViewModelService, 21 | ) {} 22 | 23 | ngOnInit() { 24 | this.vm.init(); 25 | } 26 | 27 | ngOnDestroy() { 28 | this.vm.dispose(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/app/customers/customers-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { CustomerListComponent } from './components/customer-list/customer-list.component'; 5 | import { CustomerPageComponent } from './components/customer-page/customer-page.component'; 6 | 7 | const routes: Routes = [ 8 | { path: '', component: CustomerListComponent, pathMatch: 'full' }, 9 | { path: 'new', component: CustomerPageComponent }, 10 | { path: 'edit/:id', component: CustomerPageComponent }, 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule], 16 | }) 17 | export class CustomersRoutingModule {} 18 | -------------------------------------------------------------------------------- /src/app/customers/customers.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core'; 4 | import {TranslateHttpLoader} from '@ngx-translate/http-loader'; 5 | 6 | import { CoreModule } from '../core/core.module'; 7 | 8 | import { CustomersRoutingModule } from './customers-routing.module'; 9 | import { CustomerListComponent } from './components/customer-list/customer-list.component'; 10 | import { CustomerPageComponent } from './components/customer-page/customer-page.component'; 11 | import { AppTranslateService } from '../app-translate.service'; 12 | 13 | export function HttpLoaderFactory(http: HttpClient) { 14 | return new TranslateHttpLoader(http); 15 | } 16 | 17 | @NgModule({ 18 | imports: [ 19 | CoreModule, 20 | CustomersRoutingModule, 21 | TranslateModule.forChild({ 22 | loader: {provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient]}, 23 | }) 24 | ], 25 | declarations: [CustomerListComponent, CustomerPageComponent], 26 | providers: [ 27 | { provide: TranslateService, useExisting: AppTranslateService } 28 | ] 29 | }) 30 | export class CustomersModule { } 31 | -------------------------------------------------------------------------------- /src/app/customers/enums/customer-type.enum.ts: -------------------------------------------------------------------------------- 1 | import { Enum } from '../../core/decorators/enum.decorator'; 2 | 3 | export enum CustomerType { 4 | Person, 5 | Company 6 | } 7 | 8 | Enum({ 9 | name: 'CustomerType', 10 | translatePath: 'customers.enums.type', 11 | })(CustomerType); 12 | -------------------------------------------------------------------------------- /src/app/customers/models/customer.ts: -------------------------------------------------------------------------------- 1 | import { CustomerType } from '../enums/customer-type.enum'; 2 | import { Model } from '../../core/decorators/model.decorator'; 3 | import { ModelProperty, DataValueType, DropDownConfig } from '../../core/decorators/property.decorator'; 4 | import { BaseModel } from '../../core/models/base.model'; 5 | import { Validators } from '@angular/forms'; 6 | 7 | @Model({ 8 | caption: 'customers.title', 9 | name: 'Customer', 10 | collectionName: 'customers' 11 | }) 12 | export class Customer extends BaseModel { 13 | 14 | @ModelProperty({ 15 | caption: 'common.id', 16 | dataValueType: DataValueType.Text, 17 | }) 18 | id: string; 19 | 20 | @ModelProperty({ 21 | caption: 'customers.caption.name', 22 | dataValueType: DataValueType.Text, 23 | required: true 24 | }) 25 | name: string; 26 | 27 | @ModelProperty({ 28 | caption: 'customers.caption.number', 29 | dataValueType: DataValueType.Text, 30 | readOnly: true, 31 | defaultValue: () => new Date().valueOf() 32 | }) 33 | number: string; 34 | 35 | @ModelProperty({ 36 | caption: 'customers.caption.type', 37 | dataValueType: DataValueType.DropDown, 38 | dataValueTypeConfig: { 39 | refModel: CustomerType, 40 | translatePath: 'customers.enums.type' 41 | } as DropDownConfig, 42 | required: true 43 | }) 44 | type: CustomerType; 45 | 46 | @ModelProperty({ 47 | caption: 'customers.caption.phone', 48 | dataValueType: DataValueType.Text, 49 | validators: [Validators.pattern(/^0\d{9}$/)], 50 | required: true 51 | }) 52 | phone: string; 53 | 54 | @ModelProperty({ 55 | caption: 'customers.caption.email', 56 | dataValueType: DataValueType.Text, 57 | validators: [Validators.email] 58 | }) 59 | email: string; 60 | 61 | @ModelProperty({ 62 | caption: 'customers.caption.address', 63 | dataValueType: DataValueType.Text 64 | }) 65 | address: string; 66 | 67 | @ModelProperty({ 68 | caption: 'customers.caption.notes', 69 | dataValueType: DataValueType.RichText 70 | }) 71 | notes: string; 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/app/customers/services/customer-section-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { BaseSectionViewModel } from '../../core/view-models/base-section-view-model.service'; 2 | import { Injectable, Inject, Injector } from '@angular/core'; 3 | 4 | @Injectable() 5 | export class CustomerSectionViewModelService extends BaseSectionViewModel { 6 | 7 | displayedColumns: string[] = ['number', 'name', 'phone', 'email', 'address', 'menu']; 8 | entitySchemaName = 'Customer'; 9 | 10 | constructor(@Inject(Injector) injector: Injector) { 11 | super(injector); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/customers/services/customer-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Injector, Inject } from '@angular/core'; 2 | import { BasePageViewModel } from '../../core/view-models/base-page-view-model.service'; 3 | import { Observable } from 'rxjs'; 4 | import { Customer } from '../models/customer'; 5 | import { CustomerType } from '../enums/customer-type.enum'; 6 | import { CustomerService } from './customer.service'; 7 | 8 | @Injectable() 9 | export class CustomerViewModelService extends BasePageViewModel { 10 | 11 | protected entitySchemaName = 'Customer'; 12 | protected entity = new Customer(); 13 | 14 | public get subTitle$(): Observable { 15 | return this.id 16 | ? this.translate.get('common.edit', { value: this.entity && this.entity.name }) 17 | : this.translate.get('common.create-new'); 18 | } 19 | 20 | constructor(@Inject(Injector) injector: Injector, protected customerService: CustomerService) { 21 | super(injector); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/app/customers/services/customer.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { DataService } from '../../core/data.service'; 3 | import { Customer } from '../models/customer'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class CustomerService extends DataService { 7 | 8 | collectionName = 'customers'; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/home/home.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/home/home.component.css -------------------------------------------------------------------------------- /src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-home', 5 | templateUrl: './home.component.html', 6 | styleUrls: ['./home.component.css'] 7 | }) 8 | export class HomeComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/items/components/item-features/item-features.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/items/components/item-features/item-features.component.css -------------------------------------------------------------------------------- /src/app/items/components/item-features/item-features.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/items/components/item-features/item-features.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | import { FormArray } from '@angular/forms'; 3 | import { BaseDetailViewModelService } from '../../../core/view-models/base-detail-view-model.service'; 4 | import { ItemFeaturesViewModelService } from '../../services/item-features-view-model.service'; 5 | 6 | @Component({ 7 | selector: 'app-item-features', 8 | templateUrl: './item-features.component.html', 9 | styleUrls: ['./item-features.component.css'], 10 | providers: [ 11 | ItemFeaturesViewModelService, 12 | { provide: BaseDetailViewModelService, useExisting: ItemFeaturesViewModelService }, 13 | ] 14 | }) 15 | export class ItemFeaturesComponent implements OnInit { 16 | 17 | @Input() 18 | formArray: FormArray; 19 | 20 | constructor(private vm: ItemFeaturesViewModelService) { } 21 | 22 | ngOnInit() { 23 | this.vm.init(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/app/items/components/item-list/item-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/items/components/item-list/item-list.component.css -------------------------------------------------------------------------------- /src/app/items/components/item-list/item-list.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/items/components/item-list/item-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ItemService } from '../../services/item.service'; 3 | import { ItemSectionViewModelService } from '../../services/item-section-view-model.service'; 4 | import { BaseSectionViewModel } from '../../../core/view-models/base-section-view-model.service'; 5 | import { DataService } from '../../../core/data.service'; 6 | 7 | @Component({ 8 | selector: 'app-item-list', 9 | templateUrl: './item-list.component.html', 10 | styleUrls: ['./item-list.component.css'], 11 | providers: [ 12 | { provide: BaseSectionViewModel, useClass: ItemSectionViewModelService }, 13 | { provide: DataService, useClass: ItemService } 14 | ] 15 | }) 16 | export class ItemListComponent implements OnInit { 17 | 18 | constructor( 19 | ) { } 20 | 21 | ngOnInit() { 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/app/items/components/item-page/item-page.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/items/components/item-page/item-page.component.css -------------------------------------------------------------------------------- /src/app/items/components/item-page/item-page.component.html: -------------------------------------------------------------------------------- 1 | 4 | {{ 'items.item-page' | translate }} 5 | {{ vm.subTitle$ | async }} 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
54 |
-------------------------------------------------------------------------------- /src/app/items/components/item-page/item-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import { ItemViewModelService } from '../../services/item-view-model.service'; 4 | import { DataService } from '../../../core/data.service'; 5 | import { ItemService } from '../../services/item.service'; 6 | import { BasePageViewModel } from 'src/app/core/view-models/base-page-view-model.service'; 7 | 8 | @Component({ 9 | selector: 'app-item-page', 10 | templateUrl: './item-page.component.html', 11 | styleUrls: ['./item-page.component.css'], 12 | providers: [ 13 | ItemViewModelService, 14 | { provide: BasePageViewModel, useExisting: ItemViewModelService }, 15 | { provide: DataService, useExisting: ItemService } 16 | ] 17 | }) 18 | export class ItemPageComponent implements OnInit { 19 | 20 | constructor(public vm: ItemViewModelService) { } 21 | 22 | ngOnInit() { 23 | this.vm.init(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/app/items/enums/item-feature-type.enum.ts: -------------------------------------------------------------------------------- 1 | import { Enum } from '../../core/decorators/enum.decorator'; 2 | 3 | export enum ItemFeatureType { 4 | Primary = 0, 5 | Other = 1, 6 | } 7 | 8 | Enum({ 9 | name: 'ItemFeatureType', 10 | translatePath: 'item-features.enums.type', 11 | })(ItemFeatureType); 12 | -------------------------------------------------------------------------------- /src/app/items/enums/item-type.enum.ts: -------------------------------------------------------------------------------- 1 | import { Enum } from '../../core/decorators/enum.decorator'; 2 | 3 | export enum ItemType { 4 | Goods = 0, 5 | Services = 1 6 | } 7 | 8 | Enum({ 9 | name: 'ItemType', 10 | translatePath: 'items.enums.type', 11 | })(ItemType); 12 | -------------------------------------------------------------------------------- /src/app/items/items-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { ItemListComponent } from './components/item-list/item-list.component'; 5 | import { ItemPageComponent } from './components/item-page/item-page.component'; 6 | 7 | const routes: Routes = [ 8 | { path: '', component: ItemListComponent, pathMatch: 'full' }, 9 | { path: 'new', component: ItemPageComponent }, 10 | { path: 'edit/:id', component: ItemPageComponent }, 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule], 16 | }) 17 | export class ItemsRoutingModule {} 18 | -------------------------------------------------------------------------------- /src/app/items/items.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core'; 4 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 5 | 6 | import { CoreModule } from '../core/core.module'; 7 | 8 | import { ItemsRoutingModule } from './items-routing.module'; 9 | import { ItemListComponent } from './components/item-list/item-list.component'; 10 | import { ItemPageComponent } from './components/item-page/item-page.component'; 11 | import { AppTranslateService } from '../app-translate.service'; 12 | import { ItemFeaturesComponent } from './components/item-features/item-features.component'; 13 | 14 | export function HttpLoaderFactory(http: HttpClient) { 15 | return new TranslateHttpLoader(http); 16 | } 17 | @NgModule({ 18 | imports: [ 19 | CoreModule, 20 | ItemsRoutingModule, 21 | TranslateModule.forChild({ 22 | loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient] }, 23 | // isolate: true 24 | }) 25 | ], 26 | declarations: [ItemListComponent, ItemPageComponent, ItemFeaturesComponent], 27 | providers: [ 28 | { provide: TranslateService, useExisting: AppTranslateService } 29 | ], 30 | exports: [ItemFeaturesComponent] 31 | }) 32 | export class ItemsModule { } 33 | -------------------------------------------------------------------------------- /src/app/items/models/item-feature.ts: -------------------------------------------------------------------------------- 1 | import { ItemFeatureType } from '../enums/item-feature-type.enum'; 2 | import { Model } from '../../core/decorators/model.decorator'; 3 | import { BaseModel } from '../../core/models/base.model'; 4 | import { ModelProperty, DataValueType, DropDownConfig } from '../../core/decorators/property.decorator'; 5 | 6 | @Model({ 7 | caption: 'item-feature.title', 8 | name: 'ItemFeature', 9 | collectionName: 'itemFeatures' 10 | }) 11 | export class ItemFeature extends BaseModel { 12 | 13 | @ModelProperty({ 14 | caption: 'common.id', 15 | dataValueType: DataValueType.Text, 16 | hidden: true 17 | }) 18 | id: string; 19 | 20 | @ModelProperty({ 21 | caption: 'item-features.caption.item', 22 | dataValueType: DataValueType.Text, 23 | // required: true 24 | }) 25 | itemId: string; 26 | 27 | @ModelProperty({ 28 | caption: 'item-features.caption.name', 29 | dataValueType: DataValueType.Text, 30 | required: true 31 | }) 32 | name: string; 33 | 34 | @ModelProperty({ 35 | caption: 'item-features.caption.value', 36 | dataValueType: DataValueType.Text, 37 | required: true 38 | }) 39 | value: any; 40 | 41 | @ModelProperty({ 42 | caption: 'item-features.caption.type', 43 | dataValueType: DataValueType.DropDown, 44 | dataValueTypeConfig: { 45 | refModel: ItemFeatureType 46 | } as DropDownConfig, 47 | required: true 48 | }) 49 | type: ItemFeatureType; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/app/items/models/item.ts: -------------------------------------------------------------------------------- 1 | import { ItemFeature } from './item-feature'; 2 | import { ItemType } from '../enums/item-type.enum'; 3 | import { Model } from '../../core/decorators/model.decorator'; 4 | import { ModelProperty, DataValueType, LookupConfig, DropDownConfig } from '../../core/decorators/property.decorator'; 5 | import { BaseModel } from '../../core/models/base.model'; 6 | import { Contractor } from 'src/app/contractors/models/contractor'; 7 | 8 | @Model({ 9 | caption: 'items.title', 10 | name: 'Item', 11 | collectionName: 'items' 12 | }) 13 | export class Item extends BaseModel { 14 | 15 | @ModelProperty({ 16 | caption: 'common.id', 17 | dataValueType: DataValueType.Text, 18 | }) 19 | id: string; 20 | 21 | @ModelProperty({ 22 | caption: 'items.caption.name', 23 | dataValueType: DataValueType.Text, 24 | required: true 25 | }) 26 | name: string; 27 | 28 | @ModelProperty({ 29 | caption: 'items.caption.code', 30 | dataValueType: DataValueType.Text 31 | }) 32 | code?: string; 33 | 34 | @ModelProperty({ 35 | caption: 'items.caption.bar-code', 36 | dataValueType: DataValueType.Text 37 | }) 38 | barCode?: string; 39 | 40 | @ModelProperty({ 41 | caption: 'items.caption.type', 42 | dataValueType: DataValueType.DropDown, 43 | dataValueTypeConfig: { 44 | refModel: ItemType 45 | } as DropDownConfig, 46 | required: true 47 | }) 48 | type: ItemType; 49 | 50 | @ModelProperty({ 51 | caption: 'items.caption.description', 52 | dataValueType: DataValueType.Text 53 | }) 54 | description?: string; 55 | 56 | @ModelProperty({ 57 | caption: 'items.caption.price', 58 | dataValueType: DataValueType.Money, 59 | required: true 60 | }) 61 | price: number; 62 | 63 | @ModelProperty({ 64 | caption: 'items.caption.contractor', 65 | dataValueType: DataValueType.Lookup, 66 | dataValueTypeConfig: { 67 | refModel: Contractor, 68 | displayColumns: ['phone', 'email', 'address'], 69 | columns: ['phone', 'email'] 70 | } as LookupConfig 71 | }) 72 | contractor: Contractor; 73 | 74 | @ModelProperty({ 75 | caption: 'items.caption.image', 76 | dataValueType: DataValueType.Image 77 | }) 78 | imageData?: string; 79 | 80 | @ModelProperty({ 81 | caption: 'items.caption.features', 82 | dataValueType: DataValueType.Array, 83 | dataValueTypeConfig: { 84 | refModel: ItemFeature, 85 | displayColumns: ['name', 'value'], 86 | columns: ['name', 'value', 'type'] 87 | } as LookupConfig 88 | }) 89 | features: Array; 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/app/items/services/item-features-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject, Injector } from '@angular/core'; 2 | import { BaseDetailViewModelService } from '../../core/view-models/base-detail-view-model.service'; 3 | import { Observable } from 'rxjs'; 4 | 5 | @Injectable() 6 | export class ItemFeaturesViewModelService extends BaseDetailViewModelService { 7 | 8 | entitySchemaName = 'ItemFeature'; 9 | visibleFields = ['name', 'value']; 10 | 11 | constructor(@Inject(Injector) injector: Injector) { 12 | super(injector); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/items/services/item-section-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject, Injector } from '@angular/core'; 2 | import { BaseSectionViewModel } from '../../core/view-models/base-section-view-model.service'; 3 | 4 | @Injectable() 5 | export class ItemSectionViewModelService extends BaseSectionViewModel { 6 | 7 | entitySchemaName = 'Item'; 8 | displayedColumns: string[] = ['name', 'code', 'barCode', 'price', 'contractor', 'menu']; 9 | 10 | constructor(@Inject(Injector) injector: Injector) { 11 | super(injector); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/items/services/item-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Injector, Inject } from '@angular/core'; 2 | import { Validators, FormArray, FormGroup, AbstractControl } from '@angular/forms'; 3 | import { Observable } from 'rxjs'; 4 | 5 | import { BasePageViewModel } from '../../core/view-models/base-page-view-model.service'; 6 | import { Item } from '../models/item'; 7 | import { ItemType } from '../enums/item-type.enum'; 8 | import { ItemService } from './item.service'; 9 | import { LookupConfig } from '../../core/decorators/property.decorator'; 10 | import { ItemFeature } from '../models/item-feature'; 11 | 12 | @Injectable() 13 | export class ItemViewModelService extends BasePageViewModel { 14 | 15 | protected entitySchemaName = 'Item'; 16 | protected entity = new Item(); 17 | 18 | public get subTitle$(): Observable { 19 | return this.id 20 | ? this.translate.get('common.edit', { value: this.entity && this.entity.name }) 21 | : this.translate.get('common.create-new'); 22 | } 23 | 24 | constructor(@Inject(Injector) injector: Injector, protected itemService: ItemService) { 25 | super(injector); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/app/items/services/item.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { DataService } from '../../core/data.service'; 3 | import { Item } from '../models/item'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class ItemService extends DataService { 7 | 8 | collectionName = 'items'; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/orders/components/order-features/order-features.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/orders/components/order-features/order-features.component.css -------------------------------------------------------------------------------- /src/app/orders/components/order-features/order-features.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/orders/components/order-features/order-features.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | import { FormArray } from '@angular/forms'; 3 | 4 | import { OrderFeaturesViewModelService } from '../../services/order-features-view-model.service'; 5 | import { BaseDetailViewModelService } from 'src/app/core/view-models/base-detail-view-model.service'; 6 | 7 | @Component({ 8 | selector: 'app-order-features', 9 | templateUrl: './order-features.component.html', 10 | styleUrls: ['./order-features.component.css'], 11 | providers: [ 12 | OrderFeaturesViewModelService, 13 | { provide: BaseDetailViewModelService, useExisting: OrderFeaturesViewModelService }, 14 | ] 15 | }) 16 | export class OrderFeaturesComponent implements OnInit { 17 | 18 | @Input() 19 | formArray: FormArray; 20 | 21 | constructor(private vm: OrderFeaturesViewModelService) { } 22 | 23 | ngOnInit() { 24 | this.vm.init(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/app/orders/components/order-list/order-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/orders/components/order-list/order-list.component.css -------------------------------------------------------------------------------- /src/app/orders/components/order-list/order-list.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/orders/components/order-list/order-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Order } from '../../models/order'; 3 | import { OrderSectionViewModelService } from '../../services/order-section-view-model.service'; 4 | import { OrderService } from '../../services/order.service'; 5 | import { BaseSectionViewModel } from '../../../core/view-models/base-section-view-model.service'; 6 | import { DataService } from '../../../core/data.service'; 7 | 8 | @Component({ 9 | selector: 'app-order-list', 10 | templateUrl: './order-list.component.html', 11 | styleUrls: ['./order-list.component.css'], 12 | providers: [ 13 | { provide: BaseSectionViewModel, useClass: OrderSectionViewModelService }, 14 | { provide: DataService, useClass: OrderService } 15 | ] 16 | }) 17 | export class OrderListComponent implements OnInit { 18 | 19 | orderList: Array; 20 | 21 | 22 | constructor( 23 | ) { } 24 | 25 | ngOnInit() { 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/app/orders/components/order-page/order-page.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/orders/components/order-page/order-page.component.css -------------------------------------------------------------------------------- /src/app/orders/components/order-page/order-page.component.html: -------------------------------------------------------------------------------- 1 | 4 | {{ 'orders.order-page' | translate }} 5 | {{ vm.subTitle$ | async }} 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 |
-------------------------------------------------------------------------------- /src/app/orders/components/order-page/order-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { OrderViewModelService } from '../../services/order-view-model.service'; 3 | import { DataService } from '../../../core/data.service'; 4 | import { OrderService } from '../../services/order.service'; 5 | import { BasePageViewModel } from 'src/app/core/view-models/base-page-view-model.service'; 6 | 7 | @Component({ 8 | selector: 'app-order-page', 9 | templateUrl: './order-page.component.html', 10 | styleUrls: ['./order-page.component.css'], 11 | providers: [ 12 | OrderViewModelService, 13 | { provide: BasePageViewModel, useExisting: OrderViewModelService }, 14 | { provide: DataService, useExisting: OrderService } 15 | ] 16 | }) 17 | export class OrderPageComponent implements OnInit { 18 | 19 | constructor(public vm: OrderViewModelService) { } 20 | 21 | ngOnInit() { 22 | this.vm.init(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/app/orders/enums/order-feature-type.enum.ts: -------------------------------------------------------------------------------- 1 | import { Enum } from '../../core/decorators/enum.decorator'; 2 | 3 | export enum OrderFeatureType { 4 | Primary = 0, 5 | Other = 1, 6 | } 7 | 8 | Enum({ 9 | name: 'OrderFeatureType', 10 | translatePath: 'order-features.enums.type', 11 | })(OrderFeatureType); 12 | -------------------------------------------------------------------------------- /src/app/orders/enums/order-status.enum.ts: -------------------------------------------------------------------------------- 1 | import { Enum } from '../../core/decorators/enum.decorator'; 2 | 3 | export enum OrderStatus { 4 | New, 5 | InProgress, 6 | Closed, 7 | Canceled 8 | } 9 | 10 | Enum({ 11 | name: 'OrderStatus', 12 | translatePath: 'orders.enums.status', 13 | })(OrderStatus); 14 | -------------------------------------------------------------------------------- /src/app/orders/enums/order-type.enum.ts: -------------------------------------------------------------------------------- 1 | import { Enum } from '../../core/decorators/enum.decorator'; 2 | 3 | export enum OrderType { 4 | Inbound, 5 | Outbound 6 | } 7 | 8 | Enum({ 9 | name: 'OrderType', 10 | translatePath: 'orders.enums.type', 11 | })(OrderType); 12 | -------------------------------------------------------------------------------- /src/app/orders/models/order-feature.ts: -------------------------------------------------------------------------------- 1 | import { OrderFeatureType } from '../enums/order-feature-type.enum'; 2 | import { Model } from '../../core/decorators/model.decorator'; 3 | import { BaseModel } from '../../core/models/base.model'; 4 | import { ModelProperty, DataValueType, DropDownConfig } from '../../core/decorators/property.decorator'; 5 | 6 | @Model({ 7 | caption: 'order-feature.title', 8 | name: 'OrderFeature', 9 | collectionName: 'orderFeatures' 10 | }) 11 | export class OrderFeature extends BaseModel { 12 | 13 | @ModelProperty({ 14 | caption: 'common.id', 15 | dataValueType: DataValueType.Text, 16 | hidden: true 17 | }) 18 | id: string; 19 | 20 | @ModelProperty({ 21 | caption: 'order-features.caption.order', 22 | dataValueType: DataValueType.Text, 23 | // required: true 24 | }) 25 | orderId: string; 26 | 27 | @ModelProperty({ 28 | caption: 'order-features.caption.name', 29 | dataValueType: DataValueType.Text, 30 | required: true 31 | }) 32 | name: string; 33 | 34 | @ModelProperty({ 35 | caption: 'order-features.caption.value', 36 | dataValueType: DataValueType.Text, 37 | required: true 38 | }) 39 | value: any; 40 | 41 | @ModelProperty({ 42 | caption: 'order-features.caption.type', 43 | dataValueType: DataValueType.DropDown, 44 | dataValueTypeConfig: { 45 | refModel: OrderFeatureType 46 | } as DropDownConfig, 47 | // required: true 48 | }) 49 | type: OrderFeatureType; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/app/orders/models/order.ts: -------------------------------------------------------------------------------- 1 | import { OrderStatus } from '../enums/order-status.enum'; 2 | import { Customer } from '../../customers/models/customer'; 3 | import { Item } from '../../items/models/item'; 4 | import { Store } from '../../stores/models/store'; 5 | import { OrderType } from '../enums/order-type.enum'; 6 | import { Model } from '../../core/decorators/model.decorator'; 7 | import { BaseModel } from '../../core/models/base.model'; 8 | import { ModelProperty, DataValueType, DropDownConfig, LookupConfig } from '../../core/decorators/property.decorator'; 9 | import { Validators } from '@angular/forms'; 10 | import { OrderFeature } from './order-feature'; 11 | import { ModelMethod, ModelMethodType, ModelMethodAction } from 'src/app/core/decorators/method.decorator'; 12 | import { OrderViewModelService } from '../services/order-view-model.service'; 13 | 14 | @Model({ 15 | caption: 'orders.title', 16 | name: 'Order', 17 | collectionName: 'orders' 18 | }) 19 | export class Order extends BaseModel { 20 | 21 | @ModelProperty({ 22 | caption: 'common.id', 23 | dataValueType: DataValueType.Text, 24 | }) 25 | id: string; 26 | 27 | @ModelProperty({ 28 | caption: 'orders.caption.number', 29 | dataValueType: DataValueType.Text, 30 | readOnly: true, 31 | defaultValue: () => new Date().valueOf() 32 | }) 33 | number: string; 34 | 35 | @ModelProperty({ 36 | caption: 'orders.caption.type', 37 | dataValueType: DataValueType.DropDown, 38 | dataValueTypeConfig: { 39 | refModel: OrderType 40 | } as DropDownConfig, 41 | required: true 42 | }) 43 | type: OrderType; 44 | 45 | @ModelProperty({ 46 | caption: 'orders.caption.status', 47 | dataValueType: DataValueType.DropDown, 48 | dataValueTypeConfig: { 49 | refModel: OrderStatus 50 | } as DropDownConfig, 51 | readOnly: true, 52 | defaultValue: OrderStatus.New 53 | }) 54 | status: OrderStatus; 55 | 56 | // TODO: Add validator - More then today 57 | @ModelProperty({ 58 | caption: 'orders.caption.date', 59 | dataValueType: DataValueType.Date, 60 | required: true, 61 | defaultValue: () => new Date() 62 | }) 63 | date: Date; 64 | 65 | @ModelProperty({ 66 | caption: 'orders.caption.customer', 67 | dataValueType: DataValueType.Lookup, 68 | dataValueTypeConfig: { 69 | refModel: Customer, 70 | displayColumns: ['name', 'phone', 'email'], 71 | columns: ['name', 'phone', 'email'], 72 | } as LookupConfig 73 | }) 74 | customer: Customer; 75 | 76 | @ModelProperty({ 77 | caption: 'orders.caption.item', 78 | dataValueType: DataValueType.Lookup, 79 | dataValueTypeConfig: { 80 | refModel: Item, 81 | displayColumns: ['code', 'barCode', 'price'], 82 | columns: ['code', 'barCode', 'price'], 83 | } as LookupConfig 84 | }) 85 | item: Item; 86 | 87 | @ModelProperty({ 88 | caption: 'orders.caption.store', 89 | dataValueType: DataValueType.Lookup, 90 | dataValueTypeConfig: { 91 | refModel: Store, 92 | displayColumns: ['code', 'phone', 'email', 'address'], 93 | columns: ['code', 'phone'], 94 | } as LookupConfig 95 | }) 96 | store: Store; 97 | 98 | @ModelProperty({ 99 | caption: 'orders.caption.quantity', 100 | dataValueType: DataValueType.Integer, 101 | required: true, 102 | validators: [Validators.min(0)] 103 | }) 104 | qty: number; 105 | 106 | @ModelProperty({ 107 | caption: 'order.caption.features', 108 | dataValueType: DataValueType.Array, 109 | dataValueTypeConfig: { 110 | refModel: OrderFeature, 111 | displayColumns: ['name', 'value'], 112 | columns: ['name', 'value', 'type'] 113 | } as LookupConfig 114 | }) 115 | features: Array; 116 | 117 | @ModelProperty({ 118 | caption: 'order.caption.transaction', 119 | dataValueType: DataValueType.Custom, 120 | readOnly: true 121 | }) 122 | transactionId: string; 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/app/orders/orders-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { OrderListComponent } from './components/order-list/order-list.component'; 5 | import { OrderPageComponent } from './components/order-page/order-page.component'; 6 | 7 | const routes: Routes = [ 8 | { path: '', component: OrderListComponent, pathMatch: 'full' }, 9 | { path: 'new', component: OrderPageComponent }, 10 | { path: 'edit/:id', component: OrderPageComponent }, 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule], 16 | }) 17 | export class OrdersRoutingModule {} 18 | -------------------------------------------------------------------------------- /src/app/orders/orders.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | 4 | import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core'; 5 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 6 | 7 | import { CoreModule } from '../core/core.module'; 8 | 9 | import { OrdersRoutingModule } from './orders-routing.module'; 10 | import { OrderListComponent } from './components/order-list/order-list.component'; 11 | import { OrderPageComponent } from './components/order-page/order-page.component'; 12 | import { AppTranslateService } from '../app-translate.service'; 13 | import { OrderFeaturesComponent } from './components/order-features/order-features.component'; 14 | 15 | export function HttpLoaderFactory(http: HttpClient) { 16 | return new TranslateHttpLoader(http); 17 | } 18 | 19 | @NgModule({ 20 | imports: [ 21 | CoreModule, 22 | OrdersRoutingModule, 23 | TranslateModule.forChild({ 24 | loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient] }, 25 | // isolate: true 26 | }) 27 | ], 28 | declarations: [OrderListComponent, OrderPageComponent, OrderFeaturesComponent], 29 | providers: [ 30 | { provide: TranslateService, useExisting: AppTranslateService } 31 | ] 32 | }) 33 | export class OrdersModule { } 34 | -------------------------------------------------------------------------------- /src/app/orders/services/order-features-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject, Injector } from '@angular/core'; 2 | import { BaseDetailViewModelService } from 'src/app/core/view-models/base-detail-view-model.service'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class OrderFeaturesViewModelService extends BaseDetailViewModelService { 8 | 9 | entitySchemaName = 'OrderFeature'; 10 | visibleFields = ['name', 'value']; 11 | 12 | constructor(@Inject(Injector) injector: Injector) { 13 | super(injector); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/orders/services/order-section-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject, Injector } from '@angular/core'; 2 | import { BaseSectionViewModel } from '../../core/view-models/base-section-view-model.service'; 3 | 4 | @Injectable() 5 | export class OrderSectionViewModelService extends BaseSectionViewModel { 6 | 7 | entitySchemaName = 'Order'; 8 | displayedColumns: string[] = ['number', 'date', 'qty', 'customer', 'item', 'store', 'menu']; 9 | 10 | constructor(@Inject(Injector) injector: Injector) { 11 | super(injector); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/orders/services/order-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Injector } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | 4 | import { BasePageViewModel } from '../../core/view-models/base-page-view-model.service'; 5 | 6 | import { Order } from '../models/order'; 7 | import { OrderType } from '../enums/order-type.enum'; 8 | import { OrderService } from './order.service'; 9 | import { OrderFeature } from '../models/order-feature'; 10 | import { Item } from 'src/app/items/models/item'; 11 | import { Guid } from 'guid-typescript'; 12 | import { OrderFeatureType } from '../enums/order-feature-type.enum'; 13 | import { TransactionService } from 'src/app/transactions/services/transaction.service'; 14 | import { OrderStatus } from '../enums/order-status.enum'; 15 | import { Transaction } from 'src/app/transactions/models/transaction'; 16 | import { TransactionType } from 'src/app/transactions/enums/transaction-type.enum'; 17 | import { TransactionStatus } from 'src/app/transactions/enums/transaction-status.enum'; 18 | import { switchMap, map, take } from 'rxjs/operators'; 19 | import { ViewModelAction } from 'src/app/core/decorators/view-model-action.decorator'; 20 | 21 | @Injectable() 22 | export class OrderViewModelService extends BasePageViewModel { 23 | 24 | entitySchemaName = 'Order'; 25 | entity = new Order(); 26 | 27 | public get subTitle$(): Observable { 28 | return this.id 29 | ? this.translate.get('common.edit', { value: this.entity && this.entity.number }) 30 | : this.translate.get('common.create-new'); 31 | } 32 | 33 | constructor( 34 | injector: Injector, 35 | protected orderService: OrderService, 36 | protected transactionService: TransactionService 37 | ) { 38 | super(injector); 39 | } 40 | 41 | initForm() { 42 | super.initForm(); 43 | this.subscribeOnItemChange(); 44 | } 45 | 46 | subscribeOnItemChange() { 47 | this.form.get('item').valueChanges.subscribe( 48 | item => this.onItemChange(item) 49 | ); 50 | } 51 | 52 | onItemChange(item: Item) { 53 | const features = item && Array.isArray(item.features) ? item.features.map(x => { 54 | let feature = new OrderFeature(); 55 | feature = Object.assign(feature, x); 56 | delete (feature as any).itemId; 57 | feature.orderId = this.entity.id; 58 | return feature; 59 | }) : []; 60 | const metadata = this.getEntitySchemaPropertyByName('features'); 61 | this.createFormArray(metadata, features); 62 | this.form.patchValue({ features }); 63 | } 64 | 65 | @ViewModelAction({ 66 | caption: 'orders.action.proceed', 67 | icon: 'trip_origin' 68 | }) 69 | proceed() { 70 | const order = this.form.getRawValue() as Order; 71 | this.transactionService.create({ 72 | date: new Date(), 73 | from: order.store, 74 | to: order.customer, 75 | orderId: order.id, 76 | qty: order.qty, 77 | type: TransactionType.Output, 78 | status: TransactionStatus.Pending 79 | } as Transaction).pipe( 80 | take(1), 81 | ) 82 | .subscribe(transactionId => { 83 | this.form.patchValue({ status: OrderStatus.InProgress, transactionId }); 84 | this.save(); 85 | }); 86 | } 87 | 88 | @ViewModelAction({ 89 | caption: 'orders.action.close', 90 | icon: 'trip_origin' 91 | }) 92 | close() { 93 | const order = this.form.getRawValue() as Order; 94 | this.transactionService.getById(order.transactionId) 95 | .pipe( 96 | take(1), 97 | map(transaction => { 98 | transaction.status = TransactionStatus.Closed; 99 | transaction.date = new Date(); 100 | return transaction; 101 | }), 102 | switchMap(transaction => this.transactionService.update(transaction.id, transaction)) 103 | ) 104 | .subscribe(transactionId => { 105 | this.form.patchValue({ status: OrderStatus.Closed, transactionId }); 106 | this.save(); 107 | }); 108 | } 109 | 110 | @ViewModelAction({ 111 | caption: 'orders.action.cancel', 112 | icon: 'trip_origin' 113 | }) 114 | cancel() { 115 | const order = this.form.getRawValue() as Order; 116 | this.transactionService.getById(order.transactionId) 117 | .pipe( 118 | take(1), 119 | map(transaction => { 120 | transaction.status = TransactionStatus.Canceled; 121 | transaction.date = new Date(); 122 | return transaction; 123 | }), 124 | switchMap(transaction => this.transactionService.update(transaction.id, transaction)) 125 | ) 126 | .subscribe(transactionId => { 127 | this.form.patchValue({ status: OrderStatus.Canceled, transactionId }); 128 | this.save(); 129 | }); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/app/orders/services/order.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { DataService } from '../../core/data.service'; 3 | import { Order } from '../models/order'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class OrderService extends DataService { 7 | 8 | collectionName = 'orders'; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/stocks/components/stock-list/stock-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/stocks/components/stock-list/stock-list.component.css -------------------------------------------------------------------------------- /src/app/stocks/components/stock-list/stock-list.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/stocks/components/stock-list/stock-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { BaseSectionViewModel } from '../../../core/view-models/base-section-view-model.service'; 3 | import { DataService } from '../../../core/data.service'; 4 | import { StockService } from '../../services/stock.service'; 5 | import { StockSectionViewModelService } from '../../services/stock-section-view-model.service'; 6 | 7 | @Component({ 8 | selector: 'app-stock-list', 9 | templateUrl: './stock-list.component.html', 10 | styleUrls: ['./stock-list.component.css'], 11 | providers: [ 12 | { provide: BaseSectionViewModel, useClass: StockSectionViewModelService }, 13 | { provide: DataService, useClass: StockService } 14 | ] 15 | }) 16 | export class StockListComponent implements OnInit { 17 | 18 | constructor( 19 | ) { } 20 | 21 | ngOnInit() { 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/app/stocks/components/stock-page/stock-page.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/stocks/components/stock-page/stock-page.component.css -------------------------------------------------------------------------------- /src/app/stocks/components/stock-page/stock-page.component.html: -------------------------------------------------------------------------------- 1 | 4 | {{ 'stocks.stock-page' | translate }} 5 | {{ vm.subTitle$ | async }} 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {{ 'stocks.caption.status' | translate }} 26 | 27 | 28 | {{status.name | translate}} 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 |
-------------------------------------------------------------------------------- /src/app/stocks/components/stock-page/stock-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { StockViewModelService } from '../../services/stock-view-model.service'; 3 | import { DataService } from '../../../core/data.service'; 4 | import { StockService } from '../../services/stock.service'; 5 | import { BasePageViewModel } from 'src/app/core/view-models/base-page-view-model.service'; 6 | 7 | @Component({ 8 | selector: 'app-stock-page', 9 | templateUrl: './stock-page.component.html', 10 | styleUrls: ['./stock-page.component.css'], 11 | providers: [ 12 | StockViewModelService, 13 | { provide: BasePageViewModel, useExisting: StockViewModelService }, 14 | { provide: DataService, useClass: StockService } 15 | ] 16 | }) 17 | export class StockPageComponent implements OnInit { 18 | 19 | constructor(public vm: StockViewModelService) { } 20 | 21 | ngOnInit() { 22 | this.vm.init(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/app/stocks/enums/stock-status.enum.ts: -------------------------------------------------------------------------------- 1 | import { Enum } from '../../core/decorators/enum.decorator'; 2 | 3 | export enum StockStatus { 4 | Available, 5 | InTransit, 6 | OnHold, 7 | OnService, 8 | } 9 | 10 | Enum({ 11 | name: 'StockStatus', 12 | translatePath: 'stocks.enums.status', 13 | })(StockStatus); 14 | -------------------------------------------------------------------------------- /src/app/stocks/models/stock.ts: -------------------------------------------------------------------------------- 1 | import { StockStatus } from '../enums/stock-status.enum'; 2 | import { Item } from '../../items/models/item'; 3 | import { Store } from '../../stores/models/store'; 4 | import { Model } from '../../core/decorators/model.decorator'; 5 | import { BaseModel } from '../../core/models/base.model'; 6 | import { ModelProperty, DataValueType, DropDownConfig, LookupConfig } from '../../core/decorators/property.decorator'; 7 | import { Validators } from '@angular/forms'; 8 | 9 | @Model({ 10 | caption: 'stocks.title', 11 | name: 'Stock', 12 | collectionName: 'stocks' 13 | }) 14 | export class Stock extends BaseModel { 15 | 16 | @ModelProperty({ 17 | caption: 'common.id', 18 | dataValueType: DataValueType.Text, 19 | }) 20 | id: string; 21 | 22 | @ModelProperty({ 23 | caption: 'stocks.caption.number', 24 | dataValueType: DataValueType.Text, 25 | readOnly: true, 26 | defaultValue: () => new Date().valueOf() 27 | }) 28 | number: string; 29 | 30 | @ModelProperty({ 31 | caption: 'stocks.caption.status', 32 | dataValueType: DataValueType.DropDown, 33 | dataValueTypeConfig: { 34 | refModel: StockStatus 35 | } as DropDownConfig, 36 | readOnly: true, 37 | defaultValue: StockStatus.Available 38 | }) 39 | status: StockStatus; 40 | 41 | @ModelProperty({ 42 | caption: 'stocks.caption.item', 43 | dataValueType: DataValueType.Lookup, 44 | dataValueTypeConfig: { 45 | refModel: Item, 46 | displayColumns: ['code', 'barCode', 'price'], 47 | columns: ['code', 'barCode', 'price'], 48 | } as LookupConfig 49 | }) 50 | item: Item; 51 | 52 | @ModelProperty({ 53 | caption: 'stocks.caption.store', 54 | dataValueType: DataValueType.Lookup, 55 | dataValueTypeConfig: { 56 | refModel: Store, 57 | displayColumns: ['code', 'phone', 'email', 'address'], 58 | columns: ['code', 'phone'], 59 | } as LookupConfig 60 | }) 61 | store: Store; 62 | 63 | @ModelProperty({ 64 | caption: 'stocks.caption.quantity', 65 | dataValueType: DataValueType.Integer, 66 | required: true, 67 | validators: [Validators.min(0)] 68 | }) 69 | qty: number; 70 | 71 | // TODO: Add validator - More then today 72 | @ModelProperty({ 73 | caption: 'stocks.caption.number', 74 | dataValueType: DataValueType.Date, 75 | required: true, 76 | defaultValue: () => new Date() 77 | }) 78 | date: Date; 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/app/stocks/services/stock-section-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject, Injector } from '@angular/core'; 2 | import { BaseSectionViewModel } from '../../core/view-models/base-section-view-model.service'; 3 | import { StockStatus } from '../enums/stock-status.enum'; 4 | 5 | @Injectable() 6 | export class StockSectionViewModelService extends BaseSectionViewModel { 7 | 8 | entitySchemaName = 'Stock'; 9 | displayedColumns: string[] = ['status', 'item', 'store', 'qty', 'menu']; 10 | stockStatuses: { [key: number]: string } = { 11 | [StockStatus.Available]: 'stocks.enums.status.available', 12 | [StockStatus.InTransit]: 'stocks.enums.status.in-transit', 13 | [StockStatus.OnHold]: 'stocks.enums.status.on-hold', 14 | [StockStatus.OnService]: 'stocks.enums.status.on-service', 15 | }; 16 | 17 | constructor(@Inject(Injector) injector: Injector) { 18 | super(injector); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/stocks/services/stock-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Injector, Inject } from '@angular/core'; 2 | import { Validators } from '@angular/forms'; 3 | import { Observable } from 'rxjs'; 4 | import { BasePageViewModel } from '../../core/view-models/base-page-view-model.service'; 5 | import { Stock } from '../models/stock'; 6 | import { StockService } from './stock.service'; 7 | import { StockStatus } from '../enums/stock-status.enum'; 8 | 9 | @Injectable() 10 | export class StockViewModelService extends BasePageViewModel { 11 | 12 | entitySchemaName = 'Stock'; 13 | entity = new Stock(); 14 | stockStatuses: Array<{ name: string, value: string }> = [ 15 | { value: StockStatus.Available.toString(), name: 'stocks.enums.status.available' }, 16 | { value: StockStatus.InTransit.toString(), name: 'stocks.enums.status.in-transit' }, 17 | { value: StockStatus.OnHold.toString(), name: 'stocks.enums.status.on-hold' }, 18 | { value: StockStatus.OnService.toString(), name: 'stocks.enums.status.on-service' }, 19 | ]; 20 | itemsDisplayedColumns = [ 21 | { path: 'name', title: 'items.caption.name' }, 22 | { path: 'code', title: 'items.caption.code' }, 23 | { path: 'barCode', title: 'items.caption.bar-code' }, 24 | ]; 25 | storesDisplayedColumns = [ 26 | { path: 'name', title: 'stores.caption.name' }, 27 | { path: 'code', title: 'items.caption.code' }, 28 | ]; 29 | 30 | public get subTitle$(): Observable { 31 | return this.id 32 | ? this.translate.get('common.edit', { value: this.entity && this.entity.number || '' }) 33 | : this.translate.get('common.create-new'); 34 | } 35 | 36 | constructor(@Inject(Injector) injector: Injector, protected stockService: StockService) { 37 | super(injector); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/app/stocks/services/stock.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { DataService } from '../../core/data.service'; 3 | import { Stock } from '../models/stock'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class StockService extends DataService { 7 | 8 | collectionName = 'stocks'; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/stocks/stocks-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { StockListComponent } from './components/stock-list/stock-list.component'; 5 | import { StockPageComponent } from './components/stock-page/stock-page.component'; 6 | 7 | const routes: Routes = [ 8 | { path: '', component: StockListComponent, pathMatch: 'full' }, 9 | { path: 'new', component: StockPageComponent }, 10 | { path: 'edit/:id', component: StockPageComponent }, 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule], 16 | }) 17 | export class StocksRoutingModule {} 18 | -------------------------------------------------------------------------------- /src/app/stocks/stocks.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core'; 4 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 5 | 6 | import { CoreModule } from '../core/core.module'; 7 | 8 | import { StocksRoutingModule } from './stocks-routing.module'; 9 | import { StockListComponent } from './components/stock-list/stock-list.component'; 10 | import { StockPageComponent } from './components/stock-page/stock-page.component'; 11 | import { AppTranslateService } from '../app-translate.service'; 12 | 13 | export function HttpLoaderFactory(http: HttpClient) { 14 | return new TranslateHttpLoader(http); 15 | } 16 | 17 | @NgModule({ 18 | imports: [ 19 | CoreModule, 20 | StocksRoutingModule, 21 | TranslateModule.forChild({ 22 | loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient] }, 23 | // isolate: true 24 | }) 25 | ], 26 | declarations: [StockListComponent, StockPageComponent], 27 | providers: [ 28 | { provide: TranslateService, useExisting: AppTranslateService } 29 | ] 30 | }) 31 | export class StocksModule { } 32 | -------------------------------------------------------------------------------- /src/app/stores/components/store-list/store-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/stores/components/store-list/store-list.component.css -------------------------------------------------------------------------------- /src/app/stores/components/store-list/store-list.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/stores/components/store-list/store-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { StoreSectionViewModelService } from '../../services/store-section-view-model.service'; 3 | import { BaseSectionViewModel } from '../../../core/view-models/base-section-view-model.service'; 4 | import { DataService } from '../../../core/data.service'; 5 | import { StoreService } from '../../services/store.service'; 6 | 7 | @Component({ 8 | selector: 'app-store-list', 9 | templateUrl: './store-list.component.html', 10 | styleUrls: ['./store-list.component.css'], 11 | providers: [ 12 | { provide: BaseSectionViewModel, useClass: StoreSectionViewModelService }, 13 | { provide: DataService, useClass: StoreService } 14 | ] 15 | }) 16 | export class StoreListComponent implements OnInit { 17 | 18 | constructor( 19 | ) { } 20 | 21 | ngOnInit() { 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/app/stores/components/store-page/store-page.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/stores/components/store-page/store-page.component.css -------------------------------------------------------------------------------- /src/app/stores/components/store-page/store-page.component.html: -------------------------------------------------------------------------------- 1 | 4 | {{ 'stores.store-page' | translate }} 5 | {{ vm.subTitle$ | async }} 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
-------------------------------------------------------------------------------- /src/app/stores/components/store-page/store-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { StoreViewModelService } from '../../services/store-view-model.service'; 3 | import { DataService } from '../../../core/data.service'; 4 | import { StoreService } from '../../services/store.service'; 5 | import { BasePageViewModel } from 'src/app/core/view-models/base-page-view-model.service'; 6 | 7 | @Component({ 8 | selector: 'app-store-page', 9 | templateUrl: './store-page.component.html', 10 | styleUrls: ['./store-page.component.css'], 11 | providers: [ 12 | StoreViewModelService, 13 | { provide: BasePageViewModel, useExisting: StoreViewModelService }, 14 | { provide: DataService, useClass: StoreService } 15 | ] 16 | }) 17 | export class StorePageComponent implements OnInit { 18 | 19 | constructor(public vm: StoreViewModelService) { } 20 | 21 | ngOnInit() { 22 | this.vm.init(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/app/stores/enums/store-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum StoreType { 2 | Department, 3 | BigBox, 4 | Special, 5 | Discount, 6 | ECommerce 7 | } 8 | -------------------------------------------------------------------------------- /src/app/stores/models/store.ts: -------------------------------------------------------------------------------- 1 | import { StoreType } from '../enums/store-type.enum'; 2 | import { Model } from '../../core/decorators/model.decorator'; 3 | import { BaseModel } from '../../core/models/base.model'; 4 | import { ModelProperty, DataValueType, DropDownConfig, LookupConfig } from '../../core/decorators/property.decorator'; 5 | import { Validators } from '@angular/forms'; 6 | 7 | @Model({ 8 | caption: 'stores.title', 9 | name: 'Store', 10 | collectionName: 'stores' 11 | }) 12 | export class Store extends BaseModel { 13 | 14 | @ModelProperty({ 15 | caption: 'common.id', 16 | dataValueType: DataValueType.Text, 17 | }) 18 | id: string; 19 | 20 | @ModelProperty({ 21 | caption: 'stores.caption.name', 22 | dataValueType: DataValueType.Text, 23 | required: true 24 | }) 25 | name: string; 26 | 27 | @ModelProperty({ 28 | caption: 'stores.caption.type', 29 | dataValueType: DataValueType.DropDown, 30 | dataValueTypeConfig: { 31 | refModel: StoreType 32 | } as DropDownConfig, 33 | required: true 34 | }) 35 | type: StoreType; 36 | 37 | @ModelProperty({ 38 | caption: 'stores.caption.code', 39 | dataValueType: DataValueType.Text, 40 | required: true 41 | }) 42 | code: string; 43 | 44 | @ModelProperty({ 45 | caption: 'stores.caption.address', 46 | dataValueType: DataValueType.Text, 47 | required: true 48 | }) 49 | address: string; 50 | 51 | @ModelProperty({ 52 | caption: 'stores.caption.address', 53 | dataValueType: DataValueType.Text, 54 | required: true, 55 | validators: [Validators.pattern(/^0\d{9}$/)] 56 | }) 57 | phone: string; 58 | 59 | /*@ModelProperty({ 60 | caption: 'stores.caption.stocks', 61 | dataValueType: DataValueType.Array, 62 | dataValueTypeConfig: { 63 | refModel: Stock 64 | } as LookupConfig 65 | }) 66 | stocks?: Array;*/ 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/app/stores/services/store-section-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject, Injector } from '@angular/core'; 2 | import { BaseSectionViewModel } from '../../core/view-models/base-section-view-model.service'; 3 | 4 | @Injectable() 5 | export class StoreSectionViewModelService extends BaseSectionViewModel { 6 | 7 | entitySchemaName = 'Store'; 8 | displayedColumns: string[] = ['name', 'code', 'phone', 'address', 'menu']; 9 | 10 | constructor(@Inject(Injector) injector: Injector) { 11 | super(injector); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/stores/services/store-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Injector, Inject } from '@angular/core'; 2 | 3 | import { BasePageViewModel } from '../../core/view-models/base-page-view-model.service'; 4 | import { Store } from '../models/store'; 5 | import { StoreType } from '../enums/store-type.enum'; 6 | import { StoreService } from './store.service'; 7 | import { Observable } from 'rxjs'; 8 | @Injectable() 9 | export class StoreViewModelService extends BasePageViewModel { 10 | 11 | entitySchemaName = 'Store'; 12 | entity = new Store(); 13 | 14 | public get subTitle$(): Observable { 15 | return this.id 16 | ? this.translate.get('common.edit', { value: this.entity && this.entity.name }) 17 | : this.translate.get('common.create-new'); 18 | } 19 | 20 | constructor(@Inject(Injector) injector: Injector, protected storeService: StoreService) { 21 | super(injector); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/app/stores/services/store.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { DataService } from '../../core/data.service'; 3 | import { Store } from '../models/store'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class StoreService extends DataService { 7 | 8 | collectionName = 'stores'; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/stores/stores-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { StoreListComponent } from './components/store-list/store-list.component'; 5 | import { StorePageComponent } from './components/store-page/store-page.component'; 6 | 7 | const routes: Routes = [ 8 | { path: '', component: StoreListComponent, pathMatch: 'full' }, 9 | { path: 'new', component: StorePageComponent }, 10 | { path: 'edit/:id', component: StorePageComponent }, 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule], 16 | }) 17 | export class StoresRoutingModule {} 18 | -------------------------------------------------------------------------------- /src/app/stores/stores.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core'; 4 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 5 | 6 | import { CoreModule } from '../core/core.module'; 7 | import { StoresRoutingModule } from './stores-routing.module'; 8 | import { StoreListComponent } from './components/store-list/store-list.component'; 9 | import { StorePageComponent } from './components/store-page/store-page.component'; 10 | import { AppTranslateService } from '../app-translate.service'; 11 | 12 | export function HttpLoaderFactory(http: HttpClient) { 13 | return new TranslateHttpLoader(http); 14 | } 15 | 16 | @NgModule({ 17 | imports: [ 18 | CoreModule, 19 | StoresRoutingModule, 20 | TranslateModule.forChild({ 21 | loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient] }, 22 | // isolate: true 23 | }) 24 | ], 25 | declarations: [StoreListComponent, StorePageComponent], 26 | providers: [ 27 | { provide: TranslateService, useExisting: AppTranslateService } 28 | ] 29 | }) 30 | export class StoresModule { } 31 | -------------------------------------------------------------------------------- /src/app/transactions/components/transaction-list/transaction-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/transactions/components/transaction-list/transaction-list.component.css -------------------------------------------------------------------------------- /src/app/transactions/components/transaction-list/transaction-list.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/transactions/components/transaction-list/transaction-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { TransactionSectionViewModelService } from '../../services/transaction-section-view-model.service'; 3 | import { BaseSectionViewModel } from '../../../core/view-models/base-section-view-model.service'; 4 | import { DataService } from '../../../core/data.service'; 5 | import { TransactionService } from '../../services/transaction.service'; 6 | 7 | @Component({ 8 | selector: 'app-transaction-list', 9 | templateUrl: './transaction-list.component.html', 10 | styleUrls: ['./transaction-list.component.css'], 11 | providers: [ 12 | { provide: BaseSectionViewModel, useClass: TransactionSectionViewModelService }, 13 | { provide: DataService, useClass: TransactionService } 14 | ] 15 | }) 16 | export class TransactionListComponent implements OnInit { 17 | 18 | constructor( 19 | ) { } 20 | 21 | ngOnInit() { 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/app/transactions/components/transaction-page/transaction-page.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/app/transactions/components/transaction-page/transaction-page.component.css -------------------------------------------------------------------------------- /src/app/transactions/components/transaction-page/transaction-page.component.html: -------------------------------------------------------------------------------- 1 | 3 | {{ 'transactions.transaction--page' | translate }} 4 | {{ vm.subTitle$ | async }} 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
52 |
-------------------------------------------------------------------------------- /src/app/transactions/components/transaction-page/transaction-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import { TransactionViewModelService } from '../../services/transaction-view-model.service'; 4 | import { DataService } from '../../../core/data.service'; 5 | import { TransactionService } from '../../services/transaction.service'; 6 | 7 | @Component({ 8 | selector: 'app-transaction-page', 9 | templateUrl: './transaction-page.component.html', 10 | styleUrls: ['./transaction-page.component.css'], 11 | providers: [ 12 | TransactionViewModelService, 13 | { provide: DataService, useClass: TransactionService } 14 | ] 15 | }) 16 | export class TransactionPageComponent implements OnInit { 17 | 18 | constructor(public vm: TransactionViewModelService) { } 19 | 20 | ngOnInit() { 21 | this.vm.init(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/app/transactions/enums/transaction-status.enum.ts: -------------------------------------------------------------------------------- 1 | import { Enum } from '../../core/decorators/enum.decorator'; 2 | 3 | export enum TransactionStatus { 4 | New, 5 | Pending, 6 | Canceled, 7 | Closed 8 | } 9 | 10 | Enum({ 11 | name: 'TransactionStatus', 12 | translatePath: 'transaction.enums.status', 13 | })(TransactionStatus); 14 | -------------------------------------------------------------------------------- /src/app/transactions/enums/transaction-type.enum.ts: -------------------------------------------------------------------------------- 1 | export enum TransactionType { 2 | Input, 3 | Output, 4 | Move 5 | } 6 | -------------------------------------------------------------------------------- /src/app/transactions/models/transaction.ts: -------------------------------------------------------------------------------- 1 | import { TransactionType } from '../enums/transaction-type.enum'; 2 | import { TransactionStatus } from '../enums/transaction-status.enum'; 3 | import { Store } from '../../stores/models/store'; 4 | import { Customer } from '../../customers/models/customer'; 5 | import { Order } from '../../orders/models/order'; 6 | import { Model } from '../../core/decorators/model.decorator'; 7 | import { BaseModel } from '../../core/models/base.model'; 8 | import { ModelProperty, DataValueType, DropDownConfig, LookupConfig } from '../../core/decorators/property.decorator'; 9 | 10 | @Model({ 11 | caption: 'transactions.title', 12 | name: 'Transaction', 13 | collectionName: 'transactions' 14 | }) 15 | export class Transaction extends BaseModel { 16 | 17 | @ModelProperty({ 18 | caption: 'common.id', 19 | dataValueType: DataValueType.Text, 20 | }) 21 | id: string; 22 | 23 | @ModelProperty({ 24 | caption: 'transactions.caption.type', 25 | dataValueType: DataValueType.DropDown, 26 | dataValueTypeConfig: { 27 | refModel: TransactionType 28 | } as DropDownConfig, 29 | readOnly: true 30 | }) 31 | type: TransactionType; 32 | 33 | @ModelProperty({ 34 | caption: 'transactions.caption.status', 35 | dataValueType: DataValueType.DropDown, 36 | dataValueTypeConfig: { 37 | refModel: TransactionType 38 | } as DropDownConfig, 39 | readOnly: true, 40 | defaultValue: TransactionStatus.New 41 | }) 42 | status: TransactionStatus; 43 | 44 | @ModelProperty({ 45 | caption: 'transactions.caption.from', 46 | dataValueType: DataValueType.Lookup, 47 | dataValueTypeConfig: { 48 | refModel: Store 49 | } as LookupConfig, 50 | readOnly: true 51 | }) 52 | from: Store; 53 | 54 | @ModelProperty({ 55 | caption: 'transactions.caption.to', 56 | dataValueType: DataValueType.Lookup, 57 | dataValueTypeConfig: { 58 | refModel: Customer 59 | } as LookupConfig, 60 | readOnly: true 61 | }) 62 | to: Customer; 63 | 64 | @ModelProperty({ 65 | caption: 'transactions.caption.order', 66 | dataValueType: DataValueType.Text, 67 | readOnly: true 68 | }) 69 | orderId: string; 70 | 71 | @ModelProperty({ 72 | caption: 'transactions.caption.order', 73 | dataValueType: DataValueType.Lookup, 74 | dataValueTypeConfig: { 75 | refModel: Order 76 | } as LookupConfig, 77 | readOnly: true 78 | }) 79 | order: Order; 80 | 81 | @ModelProperty({ 82 | caption: 'transactions.caption.date', 83 | dataValueType: DataValueType.Date, 84 | readOnly: true 85 | }) 86 | date: Date; 87 | 88 | @ModelProperty({ 89 | caption: 'transactions.caption.quantity', 90 | dataValueType: DataValueType.Integer, 91 | readOnly: true 92 | }) 93 | qty: number; 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/app/transactions/services/transaction-section-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject, Injector } from '@angular/core'; 2 | import { BaseSectionViewModel } from '../../core/view-models/base-section-view-model.service'; 3 | 4 | @Injectable() 5 | export class TransactionSectionViewModelService extends BaseSectionViewModel { 6 | 7 | entitySchemaName = 'Transaction'; 8 | displayedColumns: string[] = ['type', 'status', 'from', 'to', 'date', 'qty', 'menu']; 9 | saveButtonHidden = true; 10 | 11 | constructor(@Inject(Injector) injector: Injector) { 12 | super(injector); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/transactions/services/transaction-view-model.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Injector, Inject } from '@angular/core'; 2 | import { BasePageViewModel } from '../../core/view-models/base-page-view-model.service'; 3 | import { Transaction } from '../models/transaction'; 4 | import { TransactionService } from './transaction.service'; 5 | import { Observable } from 'rxjs'; 6 | 7 | @Injectable() 8 | export class TransactionViewModelService extends BasePageViewModel { 9 | 10 | entitySchemaName = 'Transaction'; 11 | entity = new Transaction(); 12 | 13 | public get subTitle$(): Observable { 14 | return this.translate.get('common.view'); 15 | } 16 | 17 | constructor(@Inject(Injector) injector: Injector, protected transactionService: TransactionService) { 18 | super(injector); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/transactions/services/transaction.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { DataService } from '../../core/data.service'; 3 | import { Transaction } from '../models/transaction'; 4 | import { Observable } from 'rxjs'; 5 | import { switchMap, map } from 'rxjs/operators'; 6 | import { Order } from 'src/app/orders/models/order'; 7 | 8 | @Injectable({ providedIn: 'root' }) 9 | export class TransactionService extends DataService { 10 | 11 | collectionName = 'transaction'; 12 | 13 | getById(id: string): Observable { 14 | const query = super.getById(id); 15 | return query.pipe( 16 | switchMap(transaction => this.db.collection('orders').doc(transaction.orderId).get() 17 | .then(orderRef => { 18 | const order = ({ 19 | id: orderRef.id, 20 | ...orderRef.data() 21 | } as unknown as Order); 22 | transaction.order = order; 23 | return transaction; 24 | })), 25 | ); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/app/transactions/transactions-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { TransactionListComponent } from './components/transaction-list/transaction-list.component'; 5 | import { TransactionPageComponent } from './components/transaction-page/transaction-page.component'; 6 | 7 | const routes: Routes = [ 8 | { path: '', component: TransactionListComponent, pathMatch: 'full' }, 9 | { path: 'new', component: TransactionPageComponent }, 10 | { path: 'edit/:id', component: TransactionPageComponent }, 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule], 16 | }) 17 | export class TransactionsRoutingModule {} 18 | -------------------------------------------------------------------------------- /src/app/transactions/transactions.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 4 | import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core'; 5 | 6 | import { CoreModule } from '../core/core.module'; 7 | 8 | import { TransactionsRoutingModule } from './transactions-routing.module'; 9 | import { TransactionListComponent } from './components/transaction-list/transaction-list.component'; 10 | import { TransactionPageComponent } from './components/transaction-page/transaction-page.component'; 11 | import { AppTranslateService } from '../app-translate.service'; 12 | 13 | export function HttpLoaderFactory(http: HttpClient) { 14 | return new TranslateHttpLoader(http); 15 | } 16 | 17 | @NgModule({ 18 | imports: [ 19 | CoreModule, 20 | TransactionsRoutingModule, 21 | TranslateModule.forChild({ 22 | loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient] }, 23 | // isolate: true 24 | }) 25 | ], 26 | declarations: [TransactionListComponent, TransactionPageComponent], 27 | providers: [ 28 | { provide: TranslateService, useExisting: AppTranslateService } 29 | ] 30 | }) 31 | export class TransactionsModule { } 32 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/i18n/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "common.app-title": "AT-CORP BPM System", 3 | "common.id": "Identity", 4 | "common.edit": "edit {{value}}", 5 | "common.create-new": "create new", 6 | "common.new-button": "New", 7 | "common.add-button": "Add", 8 | "common.back-button": "Back", 9 | "common.cancel-button": "Cancel", 10 | "common.save-button": "Save", 11 | "common.login-button": "Login", 12 | "common.messages.saved": "Saved", 13 | "common.caption.actions": "Actions", 14 | "common.menu.edit": "Edit", 15 | "common.menu.remove": "Remove", 16 | "common.menu.customers": "Customers", 17 | "common.menu.contractors": "Contractors", 18 | "common.menu.stores": "Stores", 19 | "common.menu.items": "Items", 20 | "common.menu.stocks": "Stocks", 21 | "common.menu.orders": "Orders", 22 | "common.menu.transactions": "History", 23 | "common.menu.profile": "Profile", 24 | "customers.title": "Customers", 25 | "customers.caption.name": "Name", 26 | "customers.caption.type": "Type", 27 | "customers.caption.number": "#", 28 | "customers.caption.phone": "Phone", 29 | "customers.caption.email": "E-Mail", 30 | "customers.caption.address": "Address", 31 | "customers.caption.notes": "Notes", 32 | "customers.customer-page": "Customer Page", 33 | "customers.enums.type.0": "Person", 34 | "customers.enums.type.1": "Company", 35 | "contractors.title": "Contractors", 36 | "contractors.caption.name": "Name", 37 | "contractors.caption.number": "#", 38 | "contractors.caption.phone": "Phone", 39 | "contractors.caption.email": "E-Mail", 40 | "contractors.caption.address": "Address", 41 | "contractors.caption.notes": "Notes", 42 | "contractors.contractor-page": "Contractor Page", 43 | "stores.title": "Stores", 44 | "stores.caption.name": "Name", 45 | "stores.caption.code": "Code", 46 | "stores.caption.phone": "Phone", 47 | "stores.caption.address": "Address", 48 | "stores.store-page": "Store Page", 49 | "stores.enums.type.department": "Department", 50 | "stores.enums.type.big-box": "Big Box", 51 | "stores.enums.type.special": "Special", 52 | "stores.enums.type.discount": "Discount", 53 | "stores.enums.type.e-commerce": "E-Commerce", 54 | "stores.enums.type.0": "Department", 55 | "stores.enums.type.1": "Big Box", 56 | "stores.enums.type.2": "Special", 57 | "stores.enums.type.3": "Discount", 58 | "stores.enums.type.4": "E-Commerce", 59 | "items.title": "Items", 60 | "items.caption.type": "Type", 61 | "items.caption.name": "Name", 62 | "items.caption.code": "Code", 63 | "items.caption.bar-code": "Bar Code", 64 | "items.caption.price": "Price", 65 | "items.caption.contractor": "Contractor", 66 | "items.caption.description": "Description", 67 | "items.caption.image": "Image", 68 | "items.caption.features": "Features", 69 | "items.item-page": "Item Page", 70 | "items.enums.type.goods": "Goods", 71 | "items.enums.type.services": "Services", 72 | "items.enums.type.0": "Goods", 73 | "items.enums.type.1": "Services", 74 | "item-feature.title": "Item Features", 75 | "item-features.caption.item": "Item", 76 | "item-features.caption.name": "Name", 77 | "item-features.caption.value": "Value", 78 | "item-features.caption.type": "Type", 79 | "stocks.title": "Stocks", 80 | "stocks.caption.status": "Status", 81 | "stocks.caption.item": "Item", 82 | "stocks.caption.store": "Store", 83 | "stocks.caption.quantity": "Quantity", 84 | "stocks.stock-page": "Stock Page", 85 | "stocks.enums.status.available": "Available", 86 | "stocks.enums.status.in-transit": "In Transit", 87 | "stocks.enums.status.on-hold": "On Hold", 88 | "stocks.enums.status.on-service": "On Service", 89 | "stocks.enums.status.0": "Available", 90 | "stocks.enums.status.1": "In Transit", 91 | "stocks.enums.status.2": "On Hold", 92 | "stocks.enums.status.3": "On Service", 93 | "orders.title": "Orders", 94 | "order.caption.features": "Features", 95 | "orders.caption.type": "Type", 96 | "orders.caption.number": "Number", 97 | "orders.caption.date": "Date", 98 | "orders.caption.quantity": "Quantity", 99 | "orders.caption.customer": "Customer", 100 | "orders.caption.item": "Item", 101 | "orders.caption.store": "Store", 102 | "orders.order-page": "Order Page", 103 | "orders.enums.type.0": "Inbound", 104 | "orders.enums.type.1": "Outbound", 105 | "orders.action.proceed": "Proceed", 106 | "orders.action.close": "Close", 107 | "orders.action.cancel": "Cancel", 108 | "order-feature.title": "Features", 109 | "order-features.caption.item": "Order", 110 | "order-features.caption.name": "Name", 111 | "order-features.caption.value": "Value", 112 | "order-features.caption.type": "Type", 113 | "stores.caption.type": "Type", 114 | "stores.caption.status": "Status", 115 | "stores.caption.from": "From", 116 | "stores.caption.to": "To", 117 | "stores.caption.date": "Date", 118 | "stores.caption.quantity": "Quantity", 119 | "transactions.title": "History", 120 | "transactions.transaction-page": "History Page", 121 | "transactions.caption.type": "Type", 122 | "transactions.caption.status": "Status", 123 | "transactions.caption.from": "From", 124 | "transactions.caption.to": "To", 125 | "transactions.caption.order": "Order #", 126 | "transactions.caption.date": "Date", 127 | "transactions.caption.quantity": "Quantity", 128 | "transaction.enums.status.0": "New", 129 | "transaction.enums.status.1": "Pending", 130 | "transaction.enums.status.2": "Canceled", 131 | "transaction.enums.status.3": "Closed" 132 | } -------------------------------------------------------------------------------- /src/assets/i18n/ru-RU.json: -------------------------------------------------------------------------------- 1 | { 2 | "common.app-title": "AT-CORP BPM System", 3 | "common.id": "Идентификатор", 4 | "common.edit": "редактирования {{value}}", 5 | "common.create-new": "новая запись", 6 | "common.new-button": "Создать", 7 | "common.add-button": "Добавить", 8 | "common.back-button": "Назад", 9 | "common.cancel-button": "Отмена", 10 | "common.save-button": "Сохранить", 11 | "common.messages.saved": "Сохранено", 12 | "common.caption.actions": "Действия", 13 | "common.menu.edit": "Редактировать", 14 | "common.menu.remove": "Удалить", 15 | "common.menu.customers": "Клиенты", 16 | "common.menu.contractors": "Поставщики", 17 | "common.menu.stores": "Склады", 18 | "common.menu.items": "Товары", 19 | "common.menu.stocks": "Остатки", 20 | "common.menu.orders": "Заказы", 21 | "common.menu.transactions": "История", 22 | "common.menu.profile": "Профиль", 23 | "customers.title": "Клиенты", 24 | "customers.caption.name": "Название", 25 | "customers.caption.type": "Тип", 26 | "customers.caption.number": "№", 27 | "customers.caption.phone": "Телефон", 28 | "customers.caption.email": "Эл. адрес", 29 | "customers.caption.address": "Адрес", 30 | "customers.customer-page": "Клиент", 31 | "customers.enums.type.0": "Физ. лицо", 32 | "customers.enums.type.1": "Юр. лицо", 33 | "contractors.title": "Поставщики", 34 | "contractors.caption.name": "Название", 35 | "contractors.caption.number": "№", 36 | "contractors.caption.phone": "Телефон", 37 | "contractors.caption.email": "Эл. адрес", 38 | "contractors.caption.address": "Адрес", 39 | "contractors.customer-page": "Поставщик", 40 | "stores.title": "Склады", 41 | "stores.caption.name": "Название", 42 | "stores.caption.code": "Код", 43 | "stores.caption.phone": "Телефон", 44 | "stores.caption.address": "Адрес", 45 | "stores.store-page": "Склад", 46 | "stores.enums.type.department": "Магазин", 47 | "stores.enums.type.big-box": "Торговый центр", 48 | "stores.enums.type.special": "Специальний", 49 | "stores.enums.type.discount": "Скидки", 50 | "stores.enums.type.e-commerce": "Интернет магазин", 51 | "stores.enums.type.0": "Магазин", 52 | "stores.enums.type.1": "Торговый центр", 53 | "stores.enums.type.2": "Специальний", 54 | "stores.enums.type.3": "Скидки", 55 | "stores.enums.type.4": "Интернет магазин", 56 | "items.enums.type.goods": "Товары", 57 | "items.enums.type.services": "Услуги", 58 | "items.enums.type.0": "Товары", 59 | "items.enums.type.1": "Услуги", 60 | "items.title": "Товары", 61 | "items.caption.type": "Тип", 62 | "items.caption.name": "Название", 63 | "items.caption.code": "Код", 64 | "items.caption.bar-code": "Штрих код", 65 | "items.caption.price": "Цена", 66 | "items.caption.contractor": "Поставщик", 67 | "items.caption.description": "Описание", 68 | "items.caption.image": "Фото", 69 | "items.caption.features": "Характеристики", 70 | "items.item-page": "Товар", 71 | "item-feature.title": "Характеристики товара", 72 | "item-features.caption.item": "Товар", 73 | "item-features.caption.name": "Название", 74 | "item-features.caption.value": "Значение", 75 | "item-features.caption.type": "Тип", 76 | "stocks.title": "Запасы", 77 | "stocks.caption.status": "Статус", 78 | "stocks.caption.item": "Товар", 79 | "stocks.caption.store": "Склад", 80 | "stocks.caption.quantity": "Количество", 81 | "stocks.stock-page": "Запас", 82 | "stocks.enums.status.available": "Доступный", 83 | "stocks.enums.status.in-transit": "В дороге", 84 | "stocks.enums.status.on-hold": "На удеражнии", 85 | "stocks.enums.status.on-service": "На обслуживании", 86 | "stocks.enums.status.0": "Доступный", 87 | "stocks.enums.status.1": "В дороге", 88 | "stocks.enums.status.2": "На удеражнии", 89 | "stocks.enums.status.3": "На обслуживании", 90 | "orders.title": "Заказ", 91 | "orders.order-page": "Заказ", 92 | "orders.enums.type.0": "Входящий", 93 | "orders.enums.type.1": "Исходящий", 94 | "order.caption.features": "Характеристики", 95 | "orders.caption.type": "Тип", 96 | "orders.caption.number": "Номер", 97 | "orders.caption.date": "Дата", 98 | "orders.caption.quantity": "Количество", 99 | "orders.caption.customer": "Клиент", 100 | "orders.caption.item": "Товар", 101 | "orders.caption.store": "Склад", 102 | "orders.action.proceed": "Продолжить", 103 | "orders.action.close": "Закрыть", 104 | "orders.action.cancel": "Отменить", 105 | "order-feature.title": "Характеристики заказа", 106 | "order-features.caption.item": "Заказ", 107 | "order-features.caption.name": "Название", 108 | "order-features.caption.value": "Значение", 109 | "order-features.caption.type": "Тип", 110 | "stores.caption.type": "Тип", 111 | "stores.caption.status": "Статус", 112 | "stores.caption.from": "ОТ", 113 | "stores.caption.to": "До", 114 | "stores.caption.date": "Дата", 115 | "stores.caption.quantity": "Количество", 116 | "transactions.title": "История", 117 | "transactions.transaction-page": "История", 118 | "transactions.caption.type": "Тип", 119 | "transactions.caption.status": "Статус", 120 | "transactions.caption.from": "От кого", 121 | "transactions.caption.to": "Кому", 122 | "transactions.caption.order": "№ ордера", 123 | "transactions.caption.date": "Дата", 124 | "transactions.caption.quantity": "Количество", 125 | "transaction.enums.status.0": "Новая", 126 | "transaction.enums.status.1": "В ожидании", 127 | "transaction.enums.status.2": "Отменена", 128 | "transaction.enums.status.3": "Закрыта" 129 | } -------------------------------------------------------------------------------- /src/assets/i18n/ua-UK.json: -------------------------------------------------------------------------------- 1 | { 2 | "common.app-title": "AT-CORP BPM System", 3 | "common.id": "Ідентифікатор", 4 | "common.edit": "редагування {{value}}", 5 | "common.create-new": "новий запис", 6 | "common.new-button": "Створити", 7 | "common.add-button": "Додати", 8 | "common.back-button": "Назад", 9 | "common.cancel-button": "Відміна", 10 | "common.save-button": "Зберегти", 11 | "common.messages.saved": "Збережено", 12 | "common.caption.actions": "Дії", 13 | "common.menu.edit": "Редагувати", 14 | "common.menu.remove": "Видалити", 15 | "common.menu.customers": "Клієнти", 16 | "common.menu.contractors": "Постачальники", 17 | "common.menu.stores": "Склади", 18 | "common.menu.items": "Товари", 19 | "common.menu.stocks": "Залишки", 20 | "common.menu.orders": "Замовленя", 21 | "common.menu.transactions": "Історія", 22 | "common.menu.profile": "Профіль", 23 | "customers.title": "Клієнти", 24 | "customers.caption.name": "Назва", 25 | "customers.caption.type": "Тип", 26 | "customers.customer-page": "Клієнт", 27 | "customers.caption.number": "Номер", 28 | "customers.caption.phone": "Телефон", 29 | "customers.caption.email": "Електронна адреса", 30 | "customers.caption.address": "Адреса", 31 | "customers.caption.notes": "Примітки", 32 | "customers.enums.type.0": "Фіз. особа", 33 | "customers.enums.type.1": "Юр. особа", 34 | "contractors.title": "Постачальники", 35 | "contractors.customer-page": "Постачальник", 36 | "contractors.caption.name": "Назва", 37 | "contractors.caption.number": "Номер", 38 | "contractors.caption.phone": "Телефон", 39 | "contractors.caption.email": "Електронна адреса", 40 | "contractors.caption.address": "Адреса", 41 | "contractors.caption.notes": "Примітки", 42 | "stores.title": "Склади", 43 | "stores.store-page": "Склад", 44 | "stores.caption.name": "Назва", 45 | "stores.caption.code": "Код", 46 | "stores.caption.type": "Тип", 47 | "stores.caption.status": "Статус", 48 | "stores.caption.phone": "Телефон", 49 | "stores.caption.address": "Адреса", 50 | "stores.enums.type.department": "Магазин", 51 | "stores.enums.type.big-box": "Торговий центр", 52 | "stores.enums.type.special": "Спеціальний", 53 | "stores.enums.type.discount": "Знижки", 54 | "stores.enums.type.e-commerce": "Інтернет магазин", 55 | "stores.enums.type.0": "Магазин", 56 | "stores.enums.type.1": "Торговий центр", 57 | "stores.enums.type.2": "Спеціальний", 58 | "stores.enums.type.3": "Знижки", 59 | "stores.enums.type.4": "Інтернет магазин", 60 | "items.title": "Товари", 61 | "items.caption.type": "Тип", 62 | "items.caption.name": "Назва", 63 | "items.caption.code": "Код", 64 | "items.caption.bar-code": "Штрих код", 65 | "items.caption.price": "Ціна", 66 | "items.caption.contractor": "Постачальник", 67 | "items.caption.description": "Опис", 68 | "items.caption.image": "Фото", 69 | "items.caption.features": "Характеристики", 70 | "items.item-page": "Товар", 71 | "item-feature.title": "Характеристики товару", 72 | "item-features.caption.item": "Товар", 73 | "item-features.caption.name": "Назва", 74 | "item-features.caption.value": "Значення", 75 | "item-features.caption.type": "Тип", 76 | "items.enums.type.goods": "Товари", 77 | "items.enums.type.services": "Послуги", 78 | "items.enums.type.0": "Товари", 79 | "items.enums.type.1": "Послуги", 80 | "stocks.title": "Запаси", 81 | "stocks.caption.status": "Статус", 82 | "stocks.caption.item": "Товар", 83 | "stocks.caption.store": "Склад", 84 | "stocks.caption.quantity": "Кількість", 85 | "stocks.stock-page": "Запас", 86 | "stocks.enums.status.available": "Доступний", 87 | "stocks.enums.status.in-transit": "В дорозі", 88 | "stocks.enums.status.on-hold": "На утримані", 89 | "stocks.enums.status.on-service": "На обслуговуванні", 90 | "stocks.enums.status.0": "Доступний", 91 | "stocks.enums.status.1": "В дорозі", 92 | "stocks.enums.status.2": "На утримані", 93 | "stocks.enums.status.3": "На обслуговуванні", 94 | "orders.title": "Замовлення", 95 | "orders.order-page": "Замовлення", 96 | "orders.enums.type.0": "Вхідний", 97 | "orders.enums.type.1": "Вихідний", 98 | "order.caption.features": "Характеристики замовлення", 99 | "orders.caption.type": "Тип", 100 | "orders.caption.number": "Номер", 101 | "orders.caption.date": "Дата", 102 | "orders.caption.quantity": "Кількість", 103 | "orders.caption.customer": "Клієнт", 104 | "orders.caption.item": "Товар", 105 | "orders.caption.store": "Склад", 106 | "orders.action.proceed": "Продовжити", 107 | "orders.action.close": "Закрити", 108 | "orders.action.cancel": "Відмінити", 109 | "order-feature.title": "Характеристики", 110 | "order-features.caption.item": "Замовленя", 111 | "order-features.caption.name": "Назва", 112 | "order-features.caption.value": "Значення", 113 | "order-features.caption.type": "Тип", 114 | "transactions.title": "Історія", 115 | "transactions.transaction-page": "Історія", 116 | "transactions.caption.type": "Тип", 117 | "transactions.caption.status": "Статус", 118 | "transactions.caption.from": "Від кого", 119 | "transactions.caption.to": "Кому", 120 | "transactions.caption.order": "№ ордеру", 121 | "transactions.caption.date": "Дата", 122 | "transactions.caption.quantity": "Кількість", 123 | "transaction.enums.status.0": "Нова", 124 | "transaction.enums.status.1": "В очікувані", 125 | "transaction.enums.status.2": "Відмінена", 126 | "transaction.enums.status.3": "Закрита" 127 | } -------------------------------------------------------------------------------- /src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | firebase: { 4 | apiKey: 'AIzaSyB3EuU8JMqcMaiHr4VSAqWHcAR-Q9kvbhw', 5 | authDomain: 'angular-erp-system.firebaseapp.com', 6 | databaseURL: 'https://angular-erp-system.firebaseio.com', 7 | projectId: 'angular-erp-system', 8 | storageBucket: 'angular-erp-system.appspot.com', 9 | messagingSenderId: '762384996400' 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | firebase: { 8 | apiKey: 'AIzaSyB3EuU8JMqcMaiHr4VSAqWHcAR-Q9kvbhw', 9 | authDomain: 'angular-erp-system.firebaseapp.com', 10 | databaseURL: 'https://angular-erp-system.firebaseio.com', 11 | projectId: 'angular-erp-system', 12 | storageBucket: 'angular-erp-system.appspot.com', 13 | messagingSenderId: '762384996400' 14 | } 15 | }; 16 | 17 | /* 18 | * For easier debugging in development mode, you can import the following file 19 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 20 | * 21 | * This import should be commented out in production mode because it will have a negative impact 22 | * on performance if an error is thrown. 23 | */ 24 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 25 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StashBank/angular-erp-system/b26280d1691b3d56a6d8c9f757cbef4d1b0bb82e/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularErpSystem 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage/angular-erp-system'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import 'hammerjs'; 2 | import { enableProdMode } from '@angular/core'; 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | 5 | import { AppModule } from './app/app.module'; 6 | import { environment } from './environments/environment'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic().bootstrapModule(AppModule) 13 | .catch(err => console.error(err)); 14 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { height: 100%; } 4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 5 | 6 | .mat-table { 7 | width: 100%; 8 | } 9 | 10 | app-lookup-control, 11 | app-drop-down-control, 12 | .mat-form-field { 13 | width: 100%; 14 | padding-left: 9px; 15 | padding-right: 9px; 16 | } 17 | 18 | [spacer] { 19 | flex: 1 0 auto; 20 | } 21 | 22 | @media screen and (max-width: 600px) { 23 | .mat-table { 24 | border: 0; 25 | vertical-align: middle 26 | } 27 | 28 | .mat-table caption { 29 | font-size: 1em; 30 | } 31 | 32 | .mat-table .mat-header-row { 33 | height: 3px; 34 | } 35 | 36 | .mat-table .mat-header-cell { 37 | 38 | /*border: 10px solid;*/ 39 | clip: rect(0 0 0 0); 40 | height: 1px; 41 | width: 1px; 42 | margin: -1px; 43 | padding: 0; 44 | position: absolute; 45 | } 46 | 47 | .mat-table .mat-row { 48 | border-bottom: 5px solid #ddd; 49 | display: block; 50 | } 51 | /* 52 | .mat-table .mat-row:nth-child(even) {background: #CCC} 53 | .mat-table .mat-row:nth-child(odd) {background: #FFF} 54 | */ 55 | .mat-table .mat-cell { 56 | border-bottom: 1px solid #ddd; 57 | display: block; 58 | font-size: 1em; 59 | text-align: right; 60 | height:30px; 61 | margin-bottom: 4%; 62 | padding-right: 1rem 63 | } 64 | .mat-table .mat-cell:before { 65 | /* 66 | * aria-label has no advantage, it won't be read inside a table 67 | content: attr(aria-label); 68 | */ 69 | content: attr(data-label); 70 | float: left; 71 | /*text-transform: uppercase;*/ 72 | font-weight: bold; 73 | padding-left: 1rem; 74 | font-size: .85em; 75 | } 76 | .mat-table .mat-cell:last-child { 77 | border-bottom: 0; 78 | } 79 | .mat-table .mat-cell:first-child { 80 | margin-top: 4%; 81 | } 82 | } -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es5", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [ 4 | "codelyzer" 5 | ], 6 | "rules": { 7 | "array-type": false, 8 | "arrow-parens": false, 9 | "deprecation": { 10 | "severity": "warn" 11 | }, 12 | "import-blacklist": [ 13 | true, 14 | "rxjs/Rx" 15 | ], 16 | "interface-name": false, 17 | "max-classes-per-file": false, 18 | "max-line-length": [ 19 | true, 20 | 140 21 | ], 22 | "member-access": false, 23 | "member-ordering": [ 24 | true, 25 | { 26 | "order": [ 27 | "static-field", 28 | "instance-field", 29 | "static-method", 30 | "instance-method" 31 | ] 32 | } 33 | ], 34 | "no-consecutive-blank-lines": false, 35 | "no-console": [ 36 | true, 37 | "debug", 38 | "info", 39 | "time", 40 | "timeEnd", 41 | "trace" 42 | ], 43 | "no-empty": false, 44 | "no-inferrable-types": [ 45 | true, 46 | "ignore-params" 47 | ], 48 | "no-non-null-assertion": true, 49 | "no-redundant-jsdoc": true, 50 | "no-switch-case-fall-through": true, 51 | "no-use-before-declare": true, 52 | "no-var-requires": false, 53 | "object-literal-key-quotes": [ 54 | true, 55 | "as-needed" 56 | ], 57 | "object-literal-sort-keys": false, 58 | "ordered-imports": false, 59 | "quotemark": [ 60 | true, 61 | "single" 62 | ], 63 | "trailing-comma": false, 64 | "no-output-on-prefix": true, 65 | "use-input-property-decorator": true, 66 | "use-output-property-decorator": true, 67 | "use-host-property-decorator": true, 68 | "no-input-rename": true, 69 | "no-output-rename": true, 70 | "use-life-cycle-interface": true, 71 | "use-pipe-transform-interface": true, 72 | "component-class-suffix": true, 73 | "directive-class-suffix": true 74 | } 75 | } 76 | --------------------------------------------------------------------------------