Commit 7fead81c authored by Juorder Gonzalez's avatar Juorder Gonzalez Committed by GitHub

Merge pull request #239 from ZBoxApp/salesApp

add app sales integrated with manager zbox app, only for global admin…
parents e315728f 4cee35f0
1466617142
1467382402
\ No newline at end of file
......@@ -58,7 +58,7 @@ stop-server:
kill $$PROCID; \
done
@for PROCID in $$(ps -ef | grep "[b]abel-node.*companies" | awk '{ print $$2 }'); do \
@for PROCID in $$(ps -ef | grep "[b]abel-node.*sales" | awk '{ print $$2 }'); do \
echo stopping server $$PROCID; \
kill $$PROCID; \
done
......@@ -66,4 +66,4 @@ stop-server:
start-server:
@echo Starting ZBox Manager 2.0 Test Server
@npm run server &
@npm run companies-service &
@npm run sales-service &
......@@ -75,6 +75,7 @@
"run": "webpack --progress --watch",
"run-fullmap": "webpack --progress --watch",
"companies-service": "babel-node companies-service.js",
"server": "babel-node server.js"
"server": "babel-node server.js",
"sales-service": "babel-node sales-services.js"
}
}
module.exports = {"main":{"js":"/419997bundle.js"}}
\ No newline at end of file
module.exports = {"main":{"js":"/312387bundle.js"}}
\ No newline at end of file
/**
* Created by enahum on 4/25/16.
*/
const http = require('http');
const express = require('express');
const cors = require('cors');
const path = require('path');
const fs = require('fs');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const Promise = require('bluebird');
const _ = require('lodash');
const moment = require('moment');
const port = normalizePort(process.env.PORT || '3300'); //eslint-disable-line no-process-env
const app = express();
app.set('port', port);
app.use(cors());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.get('/list', (req, res) => {
readSales().
then((data) => {
return res.json(data);
}).
catch((err) => {
return res.status(500).json(err);
});
});
app.post('/prices/mailboxes', (req, res) => {
const data = req.body;
const domainId = data.domainId;
readSales().then((data) => {
const prices = _.find(data, {domainId: domainId});
if (prices) {
return res.json(prices);
}
return res.status(404).json({
code: 404,
message: 'DomaindId ' + domainId + ' not found'
});
}).catch((err) => {
return res.status(500).json(err);
});
});
/*app.get('/sales/prices', (req, res) => {
return res.json([
{
number: 355,
link: 'http://google.com',
date: moment('2016-01-01').toJSON(),
total: '235581',
status: 1
},
{
number: 356,
link: 'http://google.com',
date: moment('2016-02-01').toJSON(),
total: '27581',
status: 2
},
{
number: 357,
date: moment('2016-02-01').toJSON(),
total: '30581',
status: 3
},
{
number: 358,
link: 'http://google.com',
date: moment('2016-03-01').toJSON(),
total: '35581',
status: 0
}
]);
});*/
// catch 404 and forward to error handler
app.use((req, res, next) => {
const err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use((err, req, res) => {
res.status(err.status || 500);
res.json({
message: err.message,
error: err
});
});
}
/**
* Create HTTP server.
*/
const server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
const p = parseInt(val, 10);
if (isNaN(p)) {
// named pipe
return val;
}
if (p >= 0) {
// port number
return p;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges'); //eslint-disable-line no-console
process.exit(1); //eslint-disable-line no-process-exit
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use'); //eslint-disable-line no-console
process.exit(1); //eslint-disable-line no-process-exit
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
const addr = server.address();
const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
console.info('ZBox Sales Test Server listening on ' + bind); //eslint-disable-line no-console
}
function readSales() {
return new Promise((resolve, reject) => {
const filename = path.join(__dirname, 'sales', 'sales.json');
fs.readFile(filename, (err, data) => {
if (err) {
return reject(err);
}
return resolve(JSON.parse(data));
});
});
}
[
{
"domainId": "fda37354-fbec-47f5-bb26-383cf2ffe7a2",
"currency": "CLP",
"prices": {
"basic": 1.490,
"professional": 1.990,
"premium": 3.490
}
},
{
"domainId": "3d450d43-54b9-401d-bc48-a77f80baf152",
"currency": "CLP",
"prices": {
"basic": 1.490,
"professional": 1.990,
"premium": 3.490
}
},
{
"domainId": null,
"currency": "CLP",
"prices": {
"basic": 20.000,
"professional": 23.000,
"premium": 40.000
}
},
{
"domainId": null,
"currency": "CLP",
"prices": {
"basic": 20.000,
"professional": 23.000,
"premium": 40.000
}
},
{
"domainId": null,
"currency": "CLP",
"prices": {
"basic": 20.000,
"professional": 23.000,
"premium": 40.000
}
}
]
......@@ -7,6 +7,7 @@ import MessageBar from '../message_bar.jsx';
import Panel from '../panel.jsx';
import ZimbraStore from '../../stores/zimbra_store.jsx';
import UserStore from '../../stores/user_store.jsx';
import * as Utils from '../../utils/utils.jsx';
......@@ -47,6 +48,7 @@ export default class DomainMailboxPlans extends React.Component {
}
const headerButtons = [
{
label: 'Ver casillas',
props: {
......@@ -63,6 +65,18 @@ export default class DomainMailboxPlans extends React.Component {
}
];
if (UserStore.isGlobalAdmin()) {
headerButtons.unshift(
{
label: 'Comprar Casillas',
props: {
className: 'btn btn-info btn-xs',
onClick: (e) => Utils.handleLink(e, `/sales/${this.props.params.id}/mailboxes`, this.props.location)
}
}
);
}
const mailboxPlans = [];
let panelBody = null;
const cos = Utils.getEnabledPlansByCosId(ZimbraStore.getAllCos());
......
......@@ -14,6 +14,7 @@ import EventStore from '../../stores/event_store.jsx';
import MailboxStore from '../../stores/mailbox_store.jsx';
import DomainStore from '../../stores/domain_store.jsx';
import ZimbraStore from '../../stores/zimbra_store.jsx';
import UserStore from '../../stores/user_store.jsx';
import Constants from '../../utils/constants.jsx';
......@@ -267,12 +268,55 @@ export default class CreateMailBox extends React.Component {
});
}
handleRadioChanged(val) {
this.setState({
handleRadioChanged(e, val) {
const {enabledAccounts} = this.state;
let needToBuy = false;
let data = {};
if (enabledAccounts) {
const keys = Object.keys(enabledAccounts);
keys.forEach((pos) => {
if (enabledAccounts[pos].cosId === val && enabledAccounts[pos].enabled < 1) {
needToBuy = true;
data = enabledAccounts[pos];
}
});
}
if (!needToBuy) {
return this.setState({
zimbraCOSId: val
});
}
e.target.checked = false;
const {zimbraCOSId} = this.state;
if (zimbraCOSId.length > 0) {
this.setState({
zimbraCOSId: ''
});
}
if (UserStore.isGlobalAdmin()) {
const options = {
title: 'Comprar Casilla',
text: `Por ahora no tienes más cupo para crear una casilla tipo <strong>${Utils.titleCase(data.plan)}</strong>, ¿Deseas comprar más?`,
html: true,
confirmButtonText: 'Si, compraré'
};
return Utils.alertToBuy((isConfirmed) => {
if (isConfirmed) {
const {id} = this.cacheDomain;
if (id) {
return Utils.handleLink(null, `/sales/${id}/mailboxes`);
}
}
}, options);
}
}
getAllDomains() {
const max = 200;
......@@ -422,7 +466,7 @@ export default class CreateMailBox extends React.Component {
keyPlans.forEach((plan) => {
if (plans[plan]) {
let isDisabled = null;
//let isDisabled = null;
let classCss = null;
let info = null;
let hasPlan = false;
......@@ -430,7 +474,7 @@ export default class CreateMailBox extends React.Component {
this.state.enabledAccounts.forEach((p) => {
if (plans[plan] === p.cosId) {
hasPlan = true;
isDisabled = p.enabled < 1 ? true : null;
//isDisabled = p.enabled < 1 ? true : null;
classCss = p.classCss;
info = (
<div>
......@@ -448,7 +492,7 @@ export default class CreateMailBox extends React.Component {
}
if (this.state.enabledAccounts && !hasPlan && null) {
isDisabled = true;
//isDisabled = true;
info = (
<div>
<span className='text-danger'>
......@@ -458,11 +502,11 @@ export default class CreateMailBox extends React.Component {
);
}
const disabledCss = isDisabled ? 'disabled' : '';
//const disabledCss = isDisabled ? 'disabled' : '';
const item = (
<label
className={`radio radio-info radio-inline pretty-input ${disabledCss}`}
className={'radio radio-info radio-inline pretty-input'}
key={plan}
>
<div className='pretty-radio'>
......@@ -470,10 +514,9 @@ export default class CreateMailBox extends React.Component {
type='radio'
className='pretty'
name='mailbox'
onChange={() => {
this.handleRadioChanged(plans[plan]);
onChange={(e) => {
this.handleRadioChanged(e, plans[plan]);
}}
disabled={isDisabled}
/>
<span></span>
</div>
......
This diff is collapsed.
This diff is collapsed.
......@@ -6,6 +6,16 @@
"zimbraProxy": "https://192.168.1.8:7071",
"dnsApiUrl": "http://zimbra.zboxapp.dev:3000",
"webMailUrl": "https://192.168.1.8:8443",
"salesAPI": {
"base": "http://localhost:8080/parse",
"getPrices": "/functions/getPrices",
"makeSale": "/functions/makeSale",
"appId": "salesZboxManagerApp"
},
"invoiceAPI": {
"currency": "CLP",
"requireTax": true
},
"timeoutRequest": 60000,
"dns": {
"url": "http://zimbra.zboxapp.dev:9081/powerdns_proxy",
......@@ -24,7 +34,22 @@
"statusCos": "btn-success",
"label": "Básica",
"isEnabledToEdit": true,
"forRights": true
"forRights": true,
"sales": [
{
"disabled": false
},
{
"disabled": true,
"label": "Precio",
"hasPrice": true
},
{
"disabled": true,
"label": "$",
"ref": "total"
}
]
},
"premium": {
"statusCos": "btn-primary2",
......@@ -32,13 +57,43 @@
"isEnabledToEdit": true,
"forRights": true,
"archiving": true,
"refer": "archiving"
"refer": "archiving",
"sales": [
{
"disabled": false
},
{
"disabled": true,
"label": "Precio",
"hasPrice": true
},
{
"disabled": true,
"label": "$",
"ref": "total"
}
]
},
"professional": {
"statusCos": "btn-primary",
"label": "Profesional",
"isEnabledToEdit": true,
"forRights": true
"forRights": true,
"sales": [
{
"disabled": false
},
{
"disabled": true,
"label": "Precio",
"hasPrice": true
},
{
"disabled": true,
"label": "$",
"ref": "total"
}
]
},
"default": false,
"archiving": {
......
......@@ -23,6 +23,7 @@ import EditMailBox from './components/mailbox/edit_mailbox.jsx';
import DistributionLists from './components/distribution/distribution_lists.jsx';
import EditDistributionList from './components/distribution/edit_distribution_lists.jsx';
import SearchView from './components/search/search.jsx';
import SalesForm from './components/sales/sales.jsx';
import * as Client from './utils/client.jsx';
import * as Utils from './utils/utils.jsx';
......@@ -207,6 +208,11 @@ function renderRootComponent() {
path='search/:query'
component={SearchView}
/>
<Route
path='sales/:domainId/mailboxes'
component={SalesForm}
/>
</Route>
<Route component={NotLoggedIn}>
<IndexRedirect to='login'/>
......
......@@ -1644,3 +1644,9 @@ label {
.overflow {
overflow: hidden;
}
.alert {
&.margin-bottom {
margin-bottom: 15px;
}
}
......@@ -779,3 +779,48 @@ export function deleteRecords(zoneUrl, record, success, error) {
return success(data);
});
}
export function getPrices(data, success, error) {
const appId = window.manager_config.salesAPI.appId;
const endpoints = window.manager_config.salesAPI;
const url = endpoints.base + endpoints.getPrices;
$.ajax({
url: url,
method: 'POST',
data: data,
headers: {
'X-Parse-Application-Id': appId
},
dataType: 'json',
success: function onSuccess(response) {
success(response);
},
error: function onError(err) {
error(err.responseJSON || err);
}
});
}
export function makeSale(data, success, error) {
const appId = window.manager_config.salesAPI.appId;
const endpoints = window.manager_config.salesAPI;
const url = endpoints.base + endpoints.makeSale;
$.ajax({
url: url,
method: 'POST',
data: data,
contentType: 'application/json',
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-REST-API-Key': 'master'
},
dataType: 'json',
success: function onSuccess(response) {
success(response);
},
error: function onError(err) {
error(err.responseJSON || err);
}
});
}
......@@ -5,6 +5,7 @@ import {browserHistory} from 'react-router';
import * as GlobalActions from '../action_creators/global_actions.jsx';
import Constants from './constants.jsx';
import ZimbraStore from '../stores/zimbra_store.jsx';
import sweetAlert from 'sweetalert';
const messageType = Constants.MessageType;
......@@ -140,7 +141,10 @@ export function areMapsEqual(a, b) {
}
export function handleLink(e, path, location) {
if (e) {
e.preventDefault();
}
if (location) {
if (`/${location.pathname}` !== path) {
GlobalActions.emitStartLoading();
......@@ -803,3 +807,37 @@ export function addEventListenerFixed(element, type, callback) {
element.addEventListener(type, callback, typeof (fixEvents[type]) !== 'undefined');
}
export function alertToBuy(callback, options) {
const defaults = {
title: 'Alerta',
type: 'info',
showCancelButton: true,
confirmButtonColor: '#DD6B55',
confirmButtonText: 'Si, continuar',
closeOnConfirm: true,
showLoaderOnConfirm: false,
animation: 'slide-from-top'
};
const optsExtended = options ? Object.assign(defaults, options) : defaults;
sweetAlert(optsExtended,
(isConfirmed) => {
if (callback && typeof callback === 'function') {
callback(isConfirmed, sweetAlert);
}
}
);
}
export function getDaysFromDate2Date(dateFrom, dateTo) {
// check if it receive and real object date or just string
const from = typeof dateFrom === 'object' ? dateFrom : new Date(dateFrom);
const to = typeof dateTo === 'object' ? dateTo : new Date(dateTo);
// get timestamp of each date and then subtract them. just get the absolute result
var timeDiff = Math.abs(from.getTime() - to.getTime());
// round to up the result, and divide result of subtract with the amount of milliseconds of one day.
var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24));
return diffDays;
}
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