I have a form with two subforms, one holds a clients details, the other the client's bookings, and this form compiles client details and bookings to make an invoice.
Due to GDPR and my own sanity I am required to delete a clients details 4 years after their last booking, but they may have many invoices over a number of years. At the moment every time i create an invoice it updates a control on the client details subform to the last booking in that invoice (as below), is there a way to make it check which date comes last and keep that one? I've had a play with Iif but am just really struggling.
At the moment i have
Private Sub Booking_subform_Exit(Cancel As Integer)
[booking contact subform].[Form]![latest booking].Value = [booking subform].[Form]![Max DATE]
End Sub
If I understand you question correctly you want to find the last date of all invoices for a client, correct? Try to use DMAX function:
DMax ( expression, domain, [criteria] )
It is similar to DLookup but it returns the highest value.
Related
I am trying to create a library management system and using a DataGridView to see a list of people defaulted on payment (last payment date is more than 2 months old).
To do this, I plan to
Query the payment table for each Member ID and pick their last record,
Then do a check on payment date on this record and display it if it is more than two months old.
Can someone please help me with the code in VB. I am not able to make much progress on my own.
You can query the payment table with a WHERE Clause
eg.(Assume you're on MSSQL)
SELECT MemberID,WhatEverYouNeed
FROM PaymentTable
WHERE PaymentDate<DATEADD(MONTH,-2,GETDATE())
It will return you a set of result, if any.
Fill it with a SqlDataAdapter. Then, bind the datatable to your DGV
Im building a system for my company to keep track of internal orders, inbetween our warehouses, we have material that goes out warehouse 1 to warehouse 2 and we kind of lose track of how much of "x" is in warehouse 1 and how much in warehouse 2, so i want to implement this access db where a user fills a form and says: order 1: 500 of "x" order 2: 300 of "y". then another user fills an exit form where he says 1 of "x" going out, so i would need the program to keep track of total order and how much as gone out to fill order 1 and so on...
My idea here is to have both an order number and an id number for each of "x" everytime someoneone assembles 1 "x" they fill the form and print a label directly from the access (i have this part working already) while keeping a record of when it was assembled, who verified and what was verified (it will work as a quality control also).
What i dont know is how to program the db so when it reaches 500 of "x", the id number for "x" starts again from 1
This is the one major issue with my program right now, i'm not experienced in access db's or vba, but im getting there with a tip and a trick from here and there, so, no need to be careful with the technical language, i will google it if i have to :p
EDIT:
The table structure goes as follows:
1 table as the main table where I record the check that is made for every product, where I include the model of the product, the said ID that I want to reset after a number of products checked, and a concatenated field that includes most of this information to generate a qr code.
Then there is a table for the Order Number, which is connected to a form to record each new order with a date/time field, the order number itself and the number of products. This number of products must then be called from the code that will count how many products have been checked to date and keep the order number field updated so we can keep track of the order.
Then there is another minor table just to get values for the form, the product models
Thank you for your answers ;)
See this MSDN Documentation
Unfortunately in Access, you cannot 'reset' an ID field, unless you move the records to a newly created table and use that table for every 500 records.
As for the user control and login form, I'm afraid those are separate questions that must be asked in a different thread.
To get you started:
You can set the RecordSource of a form to a table, and when users make entries, the data will be saved to the table. You can also use a form with controls (text boxes, comboboxes, etc.) and create a button that runs a query to insert these records into a table.
The login piece - you can encrypt the database with a password. That may/may not be sufficient.
I would suggest you change your schema, if possible. Something like the following:
Orders
OrderID (Autonumber)
ProductID (link to your Products table)
QuantityRequested
Deliverables
DeliverableID (Autonumber)
OrderID (link to your Orders table)
SequenceNumber: in the BeforeInsert event set this value equal to:
DCount("*", "Deliverables", "OrderID=" & Me.OrderID) + 1
I'm assuming that your form has a control named OrderID that is bound to the OrderID field of the Deliverables table.
The code uses the DCount() function to get the count of all the other deliverables that have already been created for this order. If this is the first deliverable, DCount() will return 0. It then adds 1 to this count to get the sequence number of the next deliverable.
If the new SequenceNumber is greater than the quantity requested, you could display a message saying that the order has been filled and cancel the creation of the Deliverable record.
This is just one approach and it is not a complete solution. I'm assuming that once assigned a sequence number a deliverable cannot be deleted. You might need to make allowances for deliverables that get lost or damaged. You could incorporate a status field to the Deliverable table to deal with this, but you would still need to make a decision about what to do with the SequenceNumber.
Probably get shot for posting this again but last attempt was put on hold so sorry in advance. i am very new at this so apologies if its a simple answer;
I created a table with name of purchaser, items purchased, date of purchase and cost of purchase. From that i wanted to create a report that would show each purchasers name only once with a combined total cost of all purchases.
I created a query that did just that using only the purchasers name and the total cost of their purchases. I then created the report from that query.
The report shows each name once with a total cost of purchases which was great except for the query continually adds those total purchases without the ability to select a date range and likewise the report shows the same info.
When i add the purchased date to the query/report so i can filter between 2 date ranges it then shows each name "X" amount of times with a total for each purchase made which is not what i am looking for as this ends up with a long report.
Hope this makes more sense than my last attempt at this question. I am very new at this so a simple answer would be great.
Thanks in advance
You need to get two parameters for the query, say [Start] and [End].
You need to add the date column twice so that it can be compared to [Start] AND [End]
You need to add the date column (on both occasions) with a Total "Where"; this tells access that the column has no other purpose than to impact a WHERE-constraint on the base dataset.
If you run into trouble, take the SQL below, correct all names in it, paste it into the query's SQL view, and then see what the design view looks like!
SELECT table.customer, Sum(table.price) AS sum
FROM table
WHERE (((table.date)>=[Start]) AND ((table.date)<=[End]))
GROUP BY table.customer;
i have a database used at work for evaluating calls, the database is somewhat dated and originally created on Access XP. Once evaluated these calls are given a score out of 5 which is entered along with other data (such as date, employee name, etc) on a form. I have the reports set up so they generate when you enter the employee name and then the start of a date period and the end of a date period, the report will then generate and show the entries made between those 2 dates. i am trying to include a section on the report which shows an average of the call score for the employee for the period chosen. I understand this may be pretty simple but i'm struggling! cheers, Kris
If you want to work out group calculations on reports, you can either put them in the group header/footer, or report header/footer (for calculations over the whole report).
In this case, placing a textbox with something like =AVG([CallScore]) as the control source in the Report Footer should work.
This page should explain more about using aggregate functions in reports: http://office.microsoft.com/en-gb/access-help/summing-in-reports-HA001122444.aspx
I have a TimeSheet table as:
CREATE TABLE TimeSheet
(
timeSheetID
employeeID
setDate
timeIn
outToLunch
returnFromLunch
timeOut
);
Employee will set his/her time sheet daily, i want to ensure that he/she doesn't cheat. What should i do?
Should i create a column that gets date/time of the system when insertion/update happens to the table and then compare the created date/time with the time employee's specified - If so in this case i will have to create date/time column for timeIn, outToLunch, returnFromLunch and timeOut. I don't know, what do you suggest?
Note: i'm concerned about tracking these 4 columns timeIn, outToLunch, returnFromLunch and timeOut
The single table design only allows an employee one break (I'm guessing that lunch is not paid). And it would be difficult to detect fraud short of auditing every record change. I'm thinking something like a two table approach would be more flexible and more secure.
Start by creating a TimeSheetDetail record for every event. i.e. Shift Start, Break Start, Break Stop, Shift End. Allow the employee to record whatever date and time in the Entered column. There may be legitimate cases where an employee forget to clock in or out.
It would be very easy to detect fraud by comparing the Entered value to the AddedOn value before Payroll or any other time an audit is needed. You could even detect small fraud where an employee constantly rounds up or down in their favor every day. Ten minutes every day over the course of a year adds up to extra week.
This design can be furthered secured by not allowing record updates or deletes.
CREATE TABLE TimeSheet
(
TimeSheetId
EmployeeId
AddedOn //populate using GETDATE()
AddedBy //populate using SUSER_SNAME()
);
CREATE TABLE TimeSheetDetail
(
TimeSheetDetailId
TimeSheetId
Type //Shift Start, Shift End, Break Start, Break End
Entered
AddedOn //populate using GETDATE()
AddedBy //populate using SUSER_SNAME()
);
If you're that concerned about employee dishonesty about their working hours, then install a manual punch card clock in/clock out system and treat them like factory shop floor workers.
Failing that, a trigger that archives off the changed record with a date-time stamp against it will allow you to see at what time every change to a timesheet was made, and a case for fraud could be made. So you'd need something like a TimeSheetHistory table, with the additional columns for time of change and user making the change (populated using GETDATE() or similar, and SUSER_SNAME() or similar if you're using Windows authentication).
Of course you are concerned about this, that is one of the basic requirements for most time sheet applications! No one should be able to change their own time sheet once submitted without a supervisor override. This is to prevent time-card fraud and thus is a legal issue and should not be subverted. Employees who get apid overtime could submit a correct timesheet for approval by the supervisor, then change it to add hours just before payroll is run and then change it back otherwise. This is critical feature that any timesheet application must have.
First, you need to have a history table to store a record of all the changes and who made them.
Next you need an update trigger that prevents updates unless a timesheet has been reopened.
Third you need a field for timesheet status. A insert/update trigger will ensure that only people in the management group can change a submitted status to a reutrned status and that no one can return his own timesheet to without a differentperson approving it. In the terms I learned when working for an audit agency, this is an internal control becasue it is known that it is far less likely that two people will join together to commit fraud than one person.