Latest work

This commit is contained in:
Dobie Wollert
2015-04-19 21:15:06 -04:00
parent 8cfff70ce0
commit 397b828024
12 changed files with 200 additions and 70 deletions

View File

@ -85,7 +85,7 @@ exports.create = function(req, res, next) {
var client = new Client({
name: req.body.name,
identifier: req.body.identifier,
identifier: req.body.identifier.toUpperCase(),
contacts: req.body.contacts,
address: req.body.address,
notes: req.body.notes,
@ -106,13 +106,44 @@ exports.create = function(req, res, next) {
})
};
exports.isUnique = function(req, res, next) {
var field = req.param('field');
var value = req.param('value');
var key = req.param('key');
if (!field || !value) {
return res.json(400, 'missing field or value');
}
var query = {};
if (field === 'identifier') {
query[field] = value.toUpperCase();
} else {
query[field] = value;
}
if (key) {
query['_id'] = { $ne: key };
}
Client.find(query)
.exec(function(err, result) {
if (err) return next(err);
res.json({
isUnique: result.length === 0
});
});
};
exports.update = function(req, res, next) {
var id = req.param('client_id');
log.info("clients.update %s %j", id, req.body);
return Client.findById(id, function(err, client) {
client.name = req.body.name;
client.identifier = req.body.identifier;
client.identifier = req.body.identifier.toUpperCase();
client.contacts = req.body.contacts;
client.address = req.body.address;
client.frequencies = req.body.frequencies;

View File

@ -132,7 +132,7 @@ module.exports = function(config, calendar) {
return callback(null);
var description = generateDescription(client, workorder, req.user, null, techs);
var techDescription = appendNotes(description, client);
var techDescription = appendNotes(description, client, workorder);
var to = req.body.emails;
var techTo = generateToLine(techs);
@ -302,7 +302,7 @@ module.exports = function(config, calendar) {
var description = generateDescription(client, workorder, createdBy, modifiedBy, techs);
var techDescription = appendNotes(description, client);
var techDescription = appendNotes(description, client, workorder);
var to = req.body.emails;
var techTo = generateToLine(techs);
@ -394,17 +394,21 @@ function generateLocation(client) {
return sprintf("%(street1)s %(street2)s %(city)s, %(state)s. %(zip)s", data);
}
function appendNotes(message, client) {
function appendNotes(message, client, workorder) {
var template =
"%(message)s\n" +
"Tech Notes:\n" +
" %(notes)s\n" +
"\n" +
"Alternative Contact:\n" +
" %(alternativeContact)s\n" +
"\n";
if (client.notes && client.notes['tech']) {
var resources = {
message: message || '',
notes: client.notes['tech'] || ''
notes: client.notes['tech'] || '',
alternativeContact: workorder.alternativeContact || ''
};
return sprintf(template, resources);
@ -491,7 +495,6 @@ function generateDescription(client, workorder, createdBy, modifiedBy) {
}
function generateAttendees(techs, workorder) {
console.log('here');
return techs.map(function(t) { return t.email; }).concat(workorder.emails);
}

View File

@ -32,6 +32,7 @@ module.exports = function(app, auth, piler, calendar, directory, config) {
var clients = require('../app/controllers/clients');
app.get('/api/clients', clients.index);
app.get('/api/clients/isUnique', clients.isUnique);
app.get('/api/clients/frequencies', clients.frequencies);
app.get('/api/clients/:client_id', clients.get);
app.get('/api/clients/:client_id/workorders', clients.workorders);

View File

@ -66,7 +66,15 @@ biomed.SchedulePmsCtrl = function($scope, Clients) {
$scope.month = moment().month();
$scope.frequencies = [];
var allData = Clients.frequencies(function() {
if (allData) {
angular.forEach(allData[0].frequencies, function(value, key) {
$scope.frequencies.push(key);
});
}
filter();
$scope.loading = false;
});
@ -80,12 +88,9 @@ biomed.SchedulePmsCtrl = function($scope, Clients) {
angular.forEach(client.frequencies, function(value, key) {
if (value[$scope.month]) {
reason.push(key);
// $scope.pms.push({
// reason: key,
// client: client
// });
if (!$scope.frequency || $scope.frequency == key) {
reason.push(key);
}
}
});
@ -120,6 +125,7 @@ biomed.SchedulePmsCtrl = function($scope, Clients) {
};
$scope.$watch('month', filter);
$scope.$watch('frequency', filter);
};
biomed.UsersIndexCtrl = function($scope, $filter, $routeParams, $location, Users, LocationBinder) {
@ -676,7 +682,7 @@ biomed.AccountingIndexCtrl = function($scope, $filter, $routeParams, Workorders,
var defaultEnd = moment().toDate();
var defaultStart = moment(defaultEnd).subtract('days', 7).toDate();
LocationBinder($scope, ['query', 'start', 'end'], {
LocationBinder($scope, ['query', 'status', 'start', 'end'], {
start: defaultStart,
end: defaultEnd
});
@ -693,6 +699,8 @@ biomed.AccountingIndexCtrl = function($scope, $filter, $routeParams, Workorders,
$scope.$watch('query', filter);
$scope.$watch('status', filter);
$scope.$watch('start', fetchData);
$scope.$watch('end', fetchData);
@ -709,10 +717,14 @@ biomed.AccountingIndexCtrl = function($scope, $filter, $routeParams, Workorders,
}
function filter() {
filteredData = $filter('filter')(data, $scope.query);
filteredData = $filter('filter')(data, {
$: $scope.query,
status: $scope.status
});
index = initialPageSize;
$scope.canLoad = true;
$scope.workorders = filteredData.slice(0, initialPageSize);
$scope.total = filteredData.length;
};
$scope.selectedCls = function(column) {
@ -729,6 +741,11 @@ biomed.AccountingIndexCtrl = function($scope, $filter, $routeParams, Workorders,
}
};
$scope.selectPage = function(status) {
console.log('SelectPage: ' + status);
$scope.status = status;
}
function fetchData() {
$scope.loading = true;
@ -971,14 +988,14 @@ biomed.WorkorderAddCtrl = function($scope, $location, Workorders, Schedule, Clie
};
function updateUsers() {
Users.index({ group: $scope.group }, function(result) {
Users.index({ group: $scope.group, perms: 'workorder.schedulable' }, function(result) {
$scope.users = result;
});
}
function updateAllUsers() {
var criteria = {};
var criteria = { perms: 'workorder.schedulable' };
Users.index(criteria, function(result) {
result.sort(function(a,b) {
@ -1029,6 +1046,24 @@ biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule,
$scope.remarks = createController();
$scope.scheduling = createSchedulingController();
function updateStatus() {
if ($scope.status.model.invoiceNumber && $scope.status.model.checkNumber) {
$scope.status.model.status = 'paid';
} else if ($scope.status.model.invoiceNumber) {
$scope.status.model.status = 'invoiced';
} else {
$scope.status.model.status = 'scheduled';
}
}
$scope.$watch('status.model.invoiceNumber', function() {
updateStatus();
});
$scope.$watch('status.model.checkNumber', function() {
updateStatus();
});
$scope.destroy = function() {
Workorders.destroy({id: $scope.master._id});
window.history.back();
@ -1185,13 +1220,13 @@ biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule,
}
function updateUsers() {
Users.index({ group: $scope.group }, function(result) {
Users.index({ group: $scope.group, perms: 'workorder.schedulable' }, function(result) {
$scope.users = result;
});
}
function updateAllUsers() {
var criteria = {};
var criteria = {perms: 'workorder.schedulable'};
Users.index(criteria, function(result) {
result.sort(function(a,b) {

View File

@ -834,4 +834,37 @@ angular.module('biomed.directives', [])
});
}
};
});
})
.directive('abUnique', function(Clients, $timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
var stop_timeout;
return scope.$watch(function() {
return ngModel.$modelValue;
}, function(name) {
$timeout.cancel(stop_timeout);
if (!name) {
ngModel.$setValidity('unique', true);
}
stop_timeout = $timeout(function() {
var keyProperty = scope.$eval(attrs.abUnique);
if (name) {
Clients.isUnique({
key: keyProperty.key,
field: keyProperty.field,
value: name
}, function(result) {
console.log('unique = ' + result.isUnique);
ngModel.$setValidity('unique', result.isUnique);
});
}
}, 200);
});
}
};
})

View File

@ -4,13 +4,14 @@ angular.module('biomed.services', [])
{ id: "@id", cmd: "@cmd" },
{
index: { method: 'GET', params: {}, isArray: true },
frequencies:{ method: 'GET', params: { cmd: 'frequencies' }, isArray: true },
frequencies: { method: 'GET', params: { cmd: 'frequencies' }, isArray: true },
get: { method: 'GET', params: { id: 0} },
create: { method: 'POST', params: {} },
update: { method: 'POST', params: { id: 0} },
destroy: { method: 'DELETE', params: { id: 0 } },
workorders: { method: 'GET', params: { id: 0, cmd: 'workorders' }, isArray: true },
tags: { method: 'GET', params: { id: 0, cmd: 'tags' }, isArray: true }
workorders: { method: 'GET', params: { id: 0, cmd: 'workorders' }, isArray: true },
tags: { method: 'GET', params: { id: 0, cmd: 'tags' }, isArray: true },
isUnique: { method: 'GET', params: { cmd: 'isUnique' } },
});
})
.factory("Posts", function($resource) {

View File

@ -11,8 +11,15 @@
<input type="text" ng-model="query" class="input-large" placeholder="Search">
<span class="add-on"><i class="icon-search"></i></span>
</div>
<a ng-click="selectPage()" class="btn">All</a>
<a ng-click="selectPage('scheduled')" class="btn">Scheduled</a>
<a ng-click="selectPage('invoiced')" class="btn">Invoiced</a>
<a ng-click="selectPage('paid')" class="btn">Paid</a>
</div>
<div class="pull-right">
<div class="pull-right">
<span class="toolbelt-text">Total: {{total}}</span>
</div>
<span class="toolbelt-text">Start: </span>
<div class="input-append">
<input ng-model="start" datepicker type="text" class="input-medium">
@ -32,9 +39,7 @@
<th style="width: 30%" ng-class="selectedCls('client.name')" ng-click="changeSorting('client.name')">Client</th>
<th style="width: 10%" ng-class="selectedCls('scheduling.start')" ng-click="changeSorting('scheduling.start')">Date</th>
<th style="width: 10%" ng-class="selectedCls('invoiceNumber')" ng-click="changeSorting('invoiceNumber')">Invoice #</th>
<th style="width: 10%" ng-class="selectedCls('invoicedOn')" ng-click="changeSorting('invoicedOn')">Invoice Date</th>
<th style="width: 10%" ng-class="selectedCls('checkNumber')" ng-click="changeSorting('checkNumber')">Check #</th>
<th style="width: 10%" ng-class="selectedCls('paidOn')" ng-click="changeSorting('paidOn')">Paid Date</th>
<th style="width: 10%" ng-class="selectedCls('status')" ng-click="changeSorting('status')">Status</th>
</tr>
</thead>
@ -48,9 +53,7 @@
<td><a ng-href="/clients/{{workorder.client._id}}">{{workorder.client.name}} ({{workorder.client.identifier}})</a></td>
<td>{{workorder.scheduling.start | date}}</td>
<td>{{workorder.invoiceNumber}}</td>
<td>{{workorder.invoicedOn | date}}</td>
<td>{{workorder.checkNumber}}</td>
<td>{{workorder.paidOn | date}}</td>
<td>{{workorder.status}}</td>
</tr>
</tbody>

View File

@ -6,7 +6,7 @@
<h1>New Client</h1>
</header>
<div class="form">
<form name="form" class="form">
<div class="form-section">
<div class="section-label">Client Name</div>
<div class="section-container">
@ -17,10 +17,20 @@
<input ng-model="model.name" type="text" name="name" class="input-xlarge">
</div>
</div>
<div class="control-group">
<div
ng-class="{ 'error': form.identifier.$invalid && !form.identifier.$pristine }"
class="control-group">
<label class="control-label">Identifier</label>
<div class="controls">
<input ng-model="model.identifier" type="text" name="identifier" requiredclass="input-xlarge">
<input
ng-model="model.identifier"
required
ab-unique="{field: 'identifier'}"
type="text"
name="identifier"
class="input-xlarge">
<span ng-show="form.identifier.$error.unique" class="help-inline">Identifier must be unique</span>
</div>
</div>
</div>
@ -190,7 +200,7 @@
<div class="form-section">
<div class="section-label">&nbsp;</div>
<div class="section-container">
<button ng-click="save()" type="button" class="btn btn-primary">Save</button>
<button ng-click="save()" ng-disabled="form.$invalid" type="button" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</form>

View File

@ -31,8 +31,15 @@
<div ng-class="{error: identificationForm.identifier.$invalid}" class="control-group">
<label class="control-label">Identifier</label>
<div class="controls">
<input ng-model="identification.model.identifier" type="text" name="identifier" required="true" class="input-xlarge">
<input
ng-model="identification.model.identifier"
ab-unique="{field: 'identifier', key: master._id}"
required="true"
type="text"
name="identifier"
class="input-xlarge">
<span ng-show="identificationForm.identifier.$error.required" class="help-inline">Required</span>
<span ng-show="identificationForm.identifier.$error.unique" class="help-inline">Identifier must be unique</span>
</div>
</div>
<div class="form-actions">

View File

@ -9,9 +9,14 @@
<div class="span12">
<div class="toolbelt">
<a href="/clients/add" class="btn btn-primary" ng-show="accountHasPermission('system.edit')">Create new Workorder</a>
<span class="toolbelt-text">Frequency:</span>
<select ng-model="frequency" name="frequency" class="input-xlarge">
<option value="">All</option>
<option ng-repeat="f in frequencies" value="{{f}}">{{f}}</option>
</select>
<div class="pull-right">
<span class="toolbelt-text">Month:</span>
<div class="input-append">
<div class="input-append">
<select ng-model="month" name="month" class="input-xlarge">
<option value="0">January</option>
<option value="1">February</option>
@ -26,8 +31,8 @@
<option value="10">November</option>
<option value="11">December</option>
</select>
<span class="add-on"><i class="icon-calendar"></i></span>
</div>
<span class="add-on"><i class="icon-calendar"></i></span>
</div>
</div>
</div>
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">

View File

@ -21,7 +21,7 @@
<tr>
<th colspan="2"></th>
<th colspan="5">Groups</th>
<th colspan="7">Permissions</th>
<th colspan="9">Permissions</th>
</tr>
<tr>
<th style="width: 15%">Name</th>
@ -35,9 +35,11 @@
<th style="width: 5%">Tags</th>
<th style="width: 5%">Messages</th>
<th style="width: 5%">Edit</th>
<th style="width: 5%">Billing</th>
<th style="width: 5%">Site</th>
<th style="width: 5%">Admin</th>
<th style="width: 5%">Frequency</th>
<th style="width: 5%">Schedulable</th>
</tr>
</thead>
<tbody>
@ -56,9 +58,11 @@
<td class="{{ checkPerm(user, 'system.tags') }}"><a ng-click="togglePerm(user, 'system.tags')"><i ng-class="{ 'icon-ok': checkPerm(user, 'system.tags'), 'icon-remove': !checkPerm(user, 'system.tags')}"></i></a></td>
<td class="{{ checkPerm(user, 'messages.receive') }}"><a ng-click="togglePerm(user, 'messages.receive')"><i ng-class="{ 'icon-ok': checkPerm(user, 'messages.receive'), 'icon-remove': !checkPerm(user, 'messages.receive')}"></i></a></td>
<td class="{{ checkPerm(user, 'system.edit') }}"><a ng-click="togglePerm(user, 'system.edit')"><i ng-class="{ 'icon-ok': checkPerm(user, 'system.edit'), 'icon-remove': !checkPerm(user, 'system.edit')}"></i></a></td>
<td class="{{ checkPerm(user, 'system.edit.billing') }}"><a ng-click="togglePerm(user, 'system.edit.billing')"><i ng-class="{ 'icon-ok': checkPerm(user, 'system.edit.billing'), 'icon-remove': !checkPerm(user, 'system.edit.billing')}"></i></a></td>
<td class="{{ checkPerm(user, 'system.site') }}"><a ng-click="togglePerm(user, 'system.site')"><i ng-class="{ 'icon-ok': checkPerm(user, 'system.site'), 'icon-remove': !checkPerm(user, 'system.site')}"></i></a></td>
<td class="{{ checkPerm(user, 'system.admin') }}"><a ng-click="togglePerm(user, 'system.admin')"><i ng-class="{ 'icon-ok': checkPerm(user, 'system.admin'), 'icon-remove': !checkPerm(user, 'system.admin')}"></i></a></td>
<td class="{{ checkPerm(user, 'client.frequency') }}"><a ng-click="togglePerm(user, 'client.frequency')"><i ng-class="{ 'icon-ok': checkPerm(user, 'client.frequency'), 'icon-remove': !checkPerm(user, 'client.frequency')}"></i></a></td>
<td class="{{ checkPerm(user, 'workorder.schedulable') }}"><a ng-click="togglePerm(user, 'workorder.schedulable')"><i ng-class="{ 'icon-ok': checkPerm(user, 'workorder.schedulable'), 'icon-remove': !checkPerm(user, 'workorder.schedulable')}"></i></a></td>
</tr>
</tbody>
</table>

View File

@ -16,39 +16,7 @@
<div class="section-label">Status</div>
<div class="section-container">
<div ng-hide="status.visible" class="form-preview">
{{master.status}}<br>
<a ng-click="status.edit()" ng-class="{disabled: editing}" ng-show="accountHasPermission('system.edit')">Edit</a>
</div>
<div ng-show="status.visible" class="form-editor">
<div class="control-group">
<label class="control-label">Status</label>
<div class="controls">
<select ng-model="status.model.status" name="status" class="input-xlarge">
<option value="scheduled">Scheduled</option>
<option value="invoiced">Invoiced</option>
<option value="paid">Paid</option>
<option value="submitted">Submitted</option>
<option value="n/a">N/A</option>
</select>
</div>
</div>
<div class="control-group" ng-show="status.model.status == 'invoiced' || status.model.status == 'paid'">
<label class="control-label">Invoice Number</label>
<div class="controls">
<input ng-model="status.model.invoiceNumber" type="text" class="input-small" ng-required="status.model.status == 'invoiced' || status.model.status == 'paid'">
</div>
</div>
<div class="control-group" ng-show="status.model.status == 'paid'">
<label class="control-label">Check Number</label>
<div class="controls">
<input ng-model="status.model.checkNumber" type="text" class="input-small" ng-required="status.model.status == 'paid'">
</div>
</div>
<div class="form-actions">
<button ng-disabled="form.$invalid" ng-click="status.save(false)" type="button" class="btn btn-primary">Save</button>
<button ng-disabled="form.$invalid" ng-click="status.save(true)" type="button" class="btn">Save & Notify</button>
<button ng-click="status.reset()" type="button" class="btn">Cancel</button>
</div>
<b>{{master.status}}</b><br>
</div>
</div>
</form>
@ -345,6 +313,35 @@
</div>
</div>
</div>
<form name="form" class="form-section" style="margin-bottom: 0">
<div class="section-label">Billing</div>
<div class="section-container">
<div ng-hide="status.visible" class="form-preview">
<span ng-show="master.invoiceNumber">Invoice Number: <b>{{master.invoiceNumber}}</b><br></span>
<span ng-show="master.checkNumber">Check Number: <b>{{master.checkNumber}}</b><br></span>
<a ng-click="status.edit()" ng-class="{disabled: editing}" ng-show="accountHasPermission('system.edit.billing')">Edit</a>
</div>
<div ng-show="status.visible" class="form-editor">
<div class="control-group">
<label class="control-label">Invoice Number</label>
<div class="controls">
<input ng-disabled="status.model.checkNumber" ng-model="status.model.invoiceNumber" type="text" class="input-small">
</div>
</div>
<div class="control-group">
<label class="control-label">Check Number</label>
<div class="controls">
<input ng-disabled="!status.model.invoiceNumber" ng-model="status.model.checkNumber" type="text" class="input-small">
</div>
</div>
<div class="form-actions">
<button ng-disabled="form.$invalid" ng-click="status.save(false)" type="button" class="btn btn-primary">Save</button>
<button ng-disabled="form.$invalid" ng-click="status.save(true)" type="button" class="btn">Save & Notify</button>
<button ng-click="status.reset()" type="button" class="btn">Cancel</button>
</div>
</div>
</div>
</form>
<div class="form-section">
<div class="section-label">Other</div>
<div class="section-container">