Commit 35d28236 authored by Bernardo Sunderhus's avatar Bernardo Sunderhus

version 0.0.1 completed

parents
/node_modules
This diff is collapsed.
{
"name": "ponto",
"version": "0.0.1",
"description": "CLI para bater o ponto",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"appdata": "^1.1.0",
"chalk": "^2.1.0",
"cli-table": "^0.3.1",
"commander": "^2.11.0",
"figlet": "^1.2.0",
"fuzzy": "^0.1.3",
"inquirer": "^3.3.0",
"inquirer-autocomplete-prompt": "^0.11.1",
"moment": "^2.18.1",
"ora": "^1.3.0"
},
"devDependencies": {
"@types/chalk": "^0.4.31",
"@types/commander": "^2.9.2",
"@types/inquirer": "0.0.35",
"@types/moment-range": "^3.0.3",
"@types/ora": "^1.3.1",
"gulp": "^3.9.1",
"rimraf": "^2.6.2",
"ts-node": "^3.3.0",
"tslib": "^1.7.1",
"tslint": "^5.7.0",
"tslint-config-standard": "^6.0.1",
"typescript": "^2.5.2"
}
}
import * as fs from 'fs'
import { join } from 'path'
import * as chalk from 'chalk'
const path = join(process.env.HOMEPATH, '.siscon-cli.json')
if (!fs.existsSync(path)) writeDefaultConfigFile()
function writeDefaultConfigFile () {
fs.writeFileSync(path, JSON.stringify(require('./default.json'), null, 2))
}
export default function getConfigFile (): ConfigFile {
return JSON.parse(fs.readFileSync(path, {encoding: 'utf8'}))
}
export type ConfigFile = {
service: {url: string, system: string | number, server: string, port: string | number}
}
import * as chalk from 'chalk'
import { Questions, prompt } from 'inquirer'
export const username: Questions = {
type: 'input',
name: 'username',
message: chalk.bold('Username:')
}
export const password: Questions = {
type: 'password',
name: 'password',
message: chalk.bold('Password:')
}
export const entry: Questions = {
type: 'confirm',
name: 'entry',
message: `Detectado operação de ${chalk.bold.italic.magenta('entrada')}, confirmar?`,
default: true
}
export const exit: Questions = {
type: 'confirm',
name: 'exit',
message: `Detectado operação de ${chalk.bold.italic.magenta('saída')}, confirmar?`,
default: true
}
export async function accessSubtask (description: string) {
const {response} = await prompt({
type: 'list',
name: 'response',
message: `A tarefa '${chalk.cyan(description)}' permite registro, porém também contém sub-tarefas, deseja acessa-las?'`,
choices: [{name: 'Registrar tarefa', value: 'N'}, {name: 'Acessar sub-tarefas', value: 'S'}]
})
return response === 'S'
}
export async function describeTask (): Promise<string> {
const response = await prompt({
type: 'input',
name: 'description',
message: 'Descreva o realizado na tarefa:',
validate: (input => Boolean(input.trim()) || chalk.red('Descrição é obrigatória'))
})
return response.description
}
export async function timeTask (time: number) {
const totalHours = Math.floor(time / 60)
const totalMinutes = time % 60
const regex = /^\s*((\d{1,2})h){0,1}\s*((\d{1,2})min){0,1}\s*$/
const response = await prompt({
type: 'input',
name: 'string',
message: `Tempo gasto na tarefa, até o máximo de ${chalk.underline.bold.italic.blue(`${totalHours}h ${totalMinutes}min`)}:`,
validate: (input => {
if (!input.trim()) return chalk.red('Tempo é obrigatório')
const [, hours] = input.match(/(\d*)h/) || [undefined, 0]
if (hours > 23) return chalk.red('Não é possível cadastrar uma atividade com mais de 23 horas')
const [, minutes] = input.match(/(\d*)min/) || [undefined, 0]
if (minutes > 59) return chalk.red('Não é possível cadastrar uma atividade com mais de 59 minutos')
const inputTime = (Number(hours) * 60) + Number(minutes)
if (time - inputTime < 0) return chalk.red('Tempo informado ultrapassa o tempo limite')
return regex.test(input) || chalk.red('Formatação inválida')
})
})
const str: string = response.string
const [, hours] = str.match(/(\d*)h/) || [undefined, 0]
const [, minutes] = str.match(/(\d*)min/) || [undefined, 0]
return (Number(hours) * 60) + Number(minutes)
}
export const confirmExit: Questions = {
type: 'confirm',
name: 'confirmExit',
message: `Tem certeza que deseja registrar operação de ${chalk.magenta('saída')}?`,
default: true
}
import { UseCase, HttpConnection, Token } from 'curiojs'
export type Item = {
_OID: string,
_Codigo: string,
_Descricao: string
}
export type Domain = {
Tipo: [{Item: [Item]}],
Projetos: [{Item: [Item]}]
}
export type Contexto = {
Usuario: [{_Nome: string}],
Domains: [Domain]
}
export type RegistroPonto = {
_DataRegistro: string,
_Tipo: string
}
export type IncluirRegistroPonto = {
UltimoRegistroPonto?: [RegistroPonto],
RegistroPonto: [RegistroPonto]
}
export type Tarefa = {
TarefasFilhas: [{Tarefa: [Tarefa]}],
_OID: string,
_Descricao: string,
_Ativo: 'S'|'N',
_PermiteRegistro: 'S'|'N'
}
export type Tarefas = [{Tarefa: [Tarefa]}]
export type ObterTarefaProjeto = {
Tarefas: Tarefas
}
export class UcRegistrarPonto extends UseCase<Promise<any>> {
static USECASEID = 788
constructor (connection?: HttpConnection, token?: Token) {
super(connection, token)
}
obterContexto (): Promise<Contexto> {
return this.request('RM_OBTEM_CONTEXTO')
}
incluirRegistroPonto (): Promise<IncluirRegistroPonto> {
return this.request('RM_INCLUIR_REGISTRO_PONTO')
}
confirmarRegistro () {
return this.request('RM_CONFIRMAR_REGISTRO')
}
obterTarefaProjeto (codigo: number | string): Promise<ObterTarefaProjeto> {
return this.request('RM_OBTEM_TAREFA_PROJETO', {OBJECTID: {_: codigo}})
}
incluirTarefa (_OID: number | string, time: number, _Descricao: string) {
const _Hora = Math.floor(time / 60)
const _Minuto = time % 60
return this.request('RM_INCLUIR_TAREFA', {Tarefa: {_OID, _Hora, _Minuto, _Descricao}})
}
}
import * as curio from 'curiojs'
export * from './UcRegistrarPonto'
import config from '../config'
const service: curio.Service = config().service
const connection = new curio.HttpConnection(service)
connection.debug = false
export const sessionManager: curio.SessionManager<Promise<any>> = new curio.SessionManager(connection)
{
"service": {
"url": "http://dev.conexops.com.br/cxClient/cxIsapiClient.dll/gatewayJSON",
"system": 0,
"server": "srp1vp1.conexops.com.br",
"port": 7266
}
}
import * as program from 'commander'
import './views/ponto'
import './views/servico'
import * as chalk from 'chalk'
const figlet = require('figlet')
program
.version('0.0.1', '-v, --version')
.parse(process.argv)
if (!program.args.length) {
figlet('SisCon - cli', function (_: Error, data: string) {
console.log(chalk.cyan(data))
program.outputHelp()
})
}
import * as inquirer from 'inquirer'
import { UcRegistrarPonto, RegistroPonto } from '../../curio'
import { entry } from '../../constants/questions'
import * as moment from 'moment'
import * as chalk from 'chalk'
export default async function entrada ({_DataRegistro}: RegistroPonto, ucRegistrarPonto: UcRegistrarPonto) {
if (!(await inquirer.prompt(entry)).entry) return
try {
await ucRegistrarPonto.confirmarRegistro()
console.log(`${chalk.cyan('!')} Registro de ${chalk.cyan('entrada')} realizado com ${chalk.green.bold.underline.italic('sucesso')} às ${chalk.blue.bold(moment(_DataRegistro).format('HH:mm'))}`)
} catch (error) {
console.log(chalk.bold.white.bgRed(`Falha ao registrar ponto. Error: ${error.message}`))
}
}
import * as program from 'commander'
import { prompt } from 'inquirer'
import { sessionManager, UcRegistrarPonto } from '../../curio'
import { Session, SystemError, BusinessError, ConnectionError } from 'curiojs'
import * as questions from '../../constants/questions'
import * as chalk from 'chalk'
import * as makeSpinner from 'ora'
import entrada from './entrada'
import saida from './saida'
program
.command('ponto')
.usage('[opções]')
.option('-u, --username <username>', 'Adicione o nome do usuário')
.option('-p, --password <password>', 'Adicione o password diretamente na linha do comando')
.action(async function ponto (options: program.CommanderStatic) {
let {username, password} = options
if (!username) username = (await prompt(questions.username)).username
if (!password) password = (await prompt(questions.password)).password
const spinner = makeSpinner()
try {
spinner.start(chalk.cyan('Realizando login...'))
const session: Session<Promise<UcRegistrarPonto>> = await sessionManager.login(username, password)
const ucRegistrarPonto = await session.open(UcRegistrarPonto)
const {Domains} = await ucRegistrarPonto.obterContexto()
const {UltimoRegistroPonto, RegistroPonto} = await ucRegistrarPonto.incluirRegistroPonto()
spinner.succeed(`Login realizado com ${chalk.bold.italic.underline.green('sucesso')}`)
if (UltimoRegistroPonto && UltimoRegistroPonto[0]._Tipo === 'E') saida(Domains[0], UltimoRegistroPonto[0], RegistroPonto[0], ucRegistrarPonto)
else entrada(RegistroPonto[0], ucRegistrarPonto)
} catch (error) {
if (error instanceof BusinessError) spinner.fail(chalk.bgRed.white.bold(error.message))
else if (error instanceof ConnectionError) spinner.fail(chalk.bgRed.white.bold(error.message))
else if (error instanceof SystemError) spinner.fail(chalk.bgRed.white.bold(error.message))
else console.error(error)
}
})
import * as program from 'commander'
import { prompt } from 'inquirer'
import { UcRegistrarPonto, RegistroPonto, Item, Domain, Tarefa } from '../../../curio'
import { exit, accessSubtask, describeTask, timeTask, confirmExit } from '../../../constants/questions'
import { BusinessError, SystemError, ConnectionError } from 'curiojs'
import * as moment from 'moment'
import * as chalk from 'chalk'
import * as fuzzy from 'fuzzy'
import * as makeSpinner from 'ora'
import promptProjeto from './projeto'
import promptTarefa from './tarefa'
const {magenta, blue, cyan, red, green} = chalk
const Table: any = require('cli-table')
export default async function saida (dominio: Domain, ultimoRegistro: RegistroPonto, registro: RegistroPonto, ucRegistrarPonto: UcRegistrarPonto) {
if (!(await prompt(exit)).exit) return
let timeElapsedInMinutes = Math.floor(moment(registro._DataRegistro).diff(ultimoRegistro._DataRegistro) / (1000 * 60))
const hours = Math.floor(timeElapsedInMinutes / 60)
const minutes = timeElapsedInMinutes % 60
console.log(`${chalk.cyan('!')} Ponto de entrada realizado à ${blue.underline.bold.italic(hours + 'h ' + minutes + 'min')}`)
const spinner = makeSpinner()
const tabelaRegistros = new Table({head: ['Projeto', 'Tarefa', 'Descrição', 'Tempo']})
try {
while (timeElapsedInMinutes > 0) {
const projeto = await promptProjeto(dominio.Projetos[0].Item)
spinner.start(cyan(`Obtendo tarefas do projeto ${projeto._Descricao}...`))
const {Tarefas} = await ucRegistrarPonto.obterTarefaProjeto(projeto._Codigo)
spinner.succeed(`Tarefas do projeto ${projeto._Descricao} obtidas com ${green.bold.italic.underline('sucesso')}`)
const tarefa = await promptTarefa(Tarefas)
if (tarefa) {
const description = await describeTask()
const time = await timeTask(timeElapsedInMinutes)
spinner.start(cyan(`Incluindo tarefa ${tarefa._Descricao}...`))
await ucRegistrarPonto.incluirTarefa(tarefa._OID, time, description)
tabelaRegistros.push([projeto._Descricao, tarefa._Descricao, description, timeToString(time)])
spinner.succeed(`Tarefa ${cyan(tarefa._Descricao)} incluída com ${green.bold.italic.underline('sucesso')}`)
timeElapsedInMinutes -= time
if (timeElapsedInMinutes > 0) {
const hours = Math.floor(timeElapsedInMinutes / 60)
const minutes = timeElapsedInMinutes % 60
console.log(`${chalk.cyan('!')} Restam ${blue.underline.bold.italic(hours + 'h ' + minutes + 'min')} a serem registradas`)
}
}
}
console.log(tabelaRegistros.toString())
if ((await prompt(confirmExit)).confirmExit) await ucRegistrarPonto.confirmarRegistro()
} catch (error) {
if (error instanceof BusinessError) spinner.fail(chalk.bgRed.white.bold(error.message))
else if (error instanceof ConnectionError) spinner.fail(chalk.bgRed.white.bold(error.message))
else console.error(error)
}
}
function timeToString (time: number) {
const hours = Math.floor(time / 60)
const hoursStr = hours ? hours + ' hora' + (hours > 1 ? 's' : '') : ''
const minutes = time % 60
const minutesStr = minutes ? minutes + ' minuto' + (minutes > 1 ? 's' : '') : ''
return `${hoursStr}${(hours && minutes) ? ' e ' : ''}${minutesStr}`
}
import * as inquirer from 'inquirer'
import { Item } from '../../../curio'
import * as chalk from 'chalk'
import * as fuzzy from 'fuzzy'
declare module 'inquirer' {
interface Question {
suggestOnly?: boolean,
source?: (answersSoFar: any, input: string) => Promise<Array<string|{name: string, value: any}>>
}
}
const {prompt, registerPrompt} = inquirer
registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'))
export default async function projeto (items: Item[], pageSize: number = 20) {
items = items.filter(item => item._Descricao)
const response = await prompt({
type: 'autocomplete',
name: 'projeto',
pageSize,
message: 'Escolha um projeto para registra tarefas:',
async source (answersSoFar, input) {
const nextItems = fuzzy.filter(
input || '',
items.map((item, i) => ({name: item._Descricao, value: i.toString()})),
{extract: (el) => el.name}
)
return nextItems.map(el => el.original)
}
})
return items[response.projeto]
}
import { prompt } from 'inquirer'
import { Item, Tarefas, Tarefa } from '../../../curio'
import { accessSubtask } from '../../../constants/questions'
import * as chalk from 'chalk'
export default async function tarefa (tarefas: Tarefas, anteriores?: Tarefas): Promise<void|Tarefa> {
let items: Tarefa[] = tarefas[0].Tarefa
items = items
.filter(item => item._Ativo === 'S' || item.TarefasFilhas)
.filter(item => item.TarefasFilhas || item._PermiteRegistro === 'S')
items.forEach(item => {
if (item.TarefasFilhas && item.TarefasFilhas[0].Tarefa.every(item => item._Ativo === 'N')) delete item.TarefasFilhas
})
if (!items.length) return console.log(`Nenhuma Tarefa ${chalk.red('ativa')} encontrada`)
const choices = (anteriores ? [{name: '..', value: '-1'}] : []).concat(
items.map((item, i) => ({
name: item.TarefasFilhas
? chalk.bold.italic.green('+ ') + item._Descricao
: (anteriores ? chalk.bold.italic.green('- ') : '') + item._Descricao,
value: i.toString()
}))
)
const response = await prompt({
type: 'list',
name: 'tarefa',
message: anteriores ? ' :' : 'Escolha uma Tarefa:',
choices
})
if (response.tarefa === '-1') return tarefa(anteriores)
const {TarefasFilhas, _PermiteRegistro, _Descricao, _OID} = items[response.tarefa]
if (!TarefasFilhas) {
if (_PermiteRegistro === 'S') return items[response.tarefa]
return console.log(`${chalk.red('×')} A Tarefa ${chalk.underline.red(_Descricao)} não permite registro`)
}
if (TarefasFilhas) {
if (_PermiteRegistro === 'S') {
if (!await accessSubtask(_Descricao)) return items[response.tarefa]
return tarefa(TarefasFilhas, tarefas)
}
return tarefa(TarefasFilhas, tarefas)
}
}
// import * as program from 'commander'
// program
// .command('serviço')
// .action(o => console.log(o.name()))
{
"compilerOptions": {
"removeComments": false,
"preserveConstEnums": true,
"sourceMap": true,
"declaration": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"suppressImplicitAnyIndexErrors": true,
"moduleResolution": "node",
"target": "es6",
"lib": [
"es5",
"es2015.iterable",
"es2015.collection",
"es2015.promise",
"dom"
]
},
"files": [
"src/index.ts"
]
}
{
"extends": "tslint-config-standard"
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment