-
Notifications
You must be signed in to change notification settings - Fork 0
/
mdlSaveForm.bas
473 lines (419 loc) · 16.9 KB
/
mdlSaveForm.bas
1
2
3
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
Option Explicit
Sub GenerateFields()
'This will generate field code for all
Dim theName As Name, tCell As Range
Set tCell = Range("tblFormInfor")
For Each theName In ThisWorkbook.Names
If theName.Name Like "txt_*" Then
tCell = theName.Name
Set tCell = tCell.Offset(0, 1)
End If
Next
End Sub
Sub ListLinks()
'Updateby20140529
Dim xIndex As Long, link As Object
Dim wb As Workbook
Set wb = Application.ActiveWorkbook
If Not IsEmpty(wb.LinkSources(xlExcelLinks)) Then
wb.Sheets.Add
xIndex = 1
For Each link In wb.LinkSources(xlExcelLinks)
Application.ActiveSheet.Cells(xIndex, 1).Value = link
xIndex = xIndex + 1
Next link
End If
End Sub
Sub TextName()
Dim rn As Range
Set rn = Range("tblFormInfor").Offset(0, 1)
While rn <> ""
If Not IsRangeValid(rn.Value) Then
rn.Offset(1) = "False"
End If
Set rn = rn.Offset(0, 1)
Wend
End Sub
Sub SearchName()
Dim tObj As Range, tSheet As Worksheet
Dim tSrc As Range
Set tSrc = Range("tmpPtr").Offset(1)
For Each tSheet In ThisWorkbook.Sheets
For Each tObj In tSheet.UsedRange
If Not tObj.Locked And tObj <> "" Then
tSrc = tSheet.Name
tSrc.Offset(0, 1) = tObj.Address
tSrc.Offset(0, 2) = tObj.Value
Set tSrc = tSrc.Offset(1)
End If
Next
Next
End Sub
Sub text_down()
Dim tName As Name
Dim tSrc As Range
Set tSrc = Range("tmpPtr").Offset(1)
For Each tName In ThisWorkbook.Names
If tName.Name Like "txt_*" Then
tSrc = tName.Name
tSrc.Offset(0, 1) = tName.RefersToRange.Address
Set tSrc = tSrc.Offset(1)
End If
Next
End Sub
Sub SaveFormData()
' This sub will do the saving of form data to access table..
' What to check:
' HHLD code, Week Num, Visit num
Dim oFile As Variant, oPath As String
oPath = GetBrowseObject(, True, "xls")
If oPath = "" Then GoTo CleanUp
oFile = Split(oPath, "|")
Dim i As Long, FileCount As Long
Dim db As New clsDbConnection
Dim StatusMsg As String, oldStatusBar As String
StatusMsg = MSG("MSG_PROCESS_FILE")
FileCount = UBound(oFile)
db.ConnectDatabase AppDatabase
oldStatusBar = Application.StatusBar
Application.DisplayStatusBar = True
ShowOff
On Error GoTo NextStep
DoEvents
For i = 0 To FileCount
If Not FileOrDirExists(CStr(oFile(i)), True) Then GoTo NextStep
Application.StatusBar = Replace(StatusMsg, "%%", oFile(i)) & " " & Format(100 * (i + 1) / (FileCount + 1), "##") & "%..."
' Just copy all reange from this worbook to our current one
CopyRangeValue CStr(oFile(i))
SaveThisForm CStr(oFile(i)), db
NextStep:
If Err.Number <> 0 Then
Err.Clear
WriteLog "Failed importing file: [" & oFile(i) & "]", "ImportError.txt"
End If
Next
CleanUp:
Application.StatusBar = oldStatusBar
Set db = Nothing
ShowOff True
End Sub
Sub SaveCurrentForm()
Dim dbs As New clsDbConnection
dbs.ConnectDatabase AppDatabase
SaveThisForm , dbs
Set dbs = Nothing
ThisWorkbook.Save
End Sub
Private Sub SaveThisForm(Optional FileObject As String, Optional db As clsDbConnection)
Dim Sql As String, HhldCode As Long
' Now we have to verify whether this record is existing and delete them first
Sql = "Delete * from tblFormInfor WHERE txt_IMS_ID ='" & Range("txt_IMS_ID") & "' AND txt_visit_date =#" & CDate(Range("txt_visit_date")) & "#;"
db.ExecuteSQL Sql
' Now just insert into database
Sql = GetSqlString()
If Sql = "" Then
If FileObject = "" Then FileObject = ThisWorkbook.Name
WriteLog "Failed importing file: [" & FileObject & "]", "ImportError.txt"
GoTo ErrHandler
End If
Sql = "INSERT INTO tblFormInfor " & Sql & ";"
db.ExecuteSQL Sql
' For sub-table
HhldCode = db.DMax("Form_ID", "tblFormInfor")
' Now select them to push into varying tables
'Key tblMembersInfor information
LoadTableToDb db, "tblMembersInfor", "tbl_hhld_members", HhldCode
ErrHandler:
End Sub
Private Sub CopyRangeValue(DstWb As String)
Dim tName As Name, oBook As Workbook
Set oBook = Workbooks.Open(DstWb, , True)
For Each tName In oBook.Names
If Not IsError(tName.RefersToRange) Then
If tName.Name Like "sub_tbl*" Then
Debug.Print tName.Name
End If
If IsRangeValid(tName.Name) Then
If Not ThisWorkbook.Names(tName.Name).RefersToRange.Locked Then
ThisWorkbook.Names(tName.Name).RefersToRange.Value = tName.RefersToRange.Value
End If
End If
End If
Next
oBook.Close False
Set oBook = Nothing
Application.CalculateFull
End Sub
Private Sub LoadTableToDb(dbs As clsDbConnection, tblName As String, tblRange As String, FormID As Long)
Dim FldHdr As String, FldValue As String
Dim HdrCell As Range, CrCell As Range
Dim ColCount As Long, RowCount As Long
Dim SqlTxt As String
Dim idv_id As Long ' id of individual
Dim sub_tableName As String
' Take the first cell
Set HdrCell = Range(tblRange).Offset(0, 1)
' set running cell to the first record
Set CrCell = HdrCell.Offset(1)
While CrCell.Offset(RowCount) <> ""
FldHdr = ""
FldValue = ""
ColCount = 0
While HdrCell.Offset(0, ColCount) <> "" And HdrCell.Offset(-2, ColCount) <> "link"
If IsError(CrCell.Offset(RowCount, ColCount)) Then GoTo NextLoop
If CrCell.Offset(RowCount, ColCount) <> "" Then
' For header row
FldHdr = FldHdr & ", " & HdrCell.Offset(0, ColCount)
' for value
Select Case HdrCell.Offset(-1, ColCount)
Case "DATETIME":
FldValue = FldValue & ", #" & CDate(CrCell.Offset(RowCount, ColCount)) & "#"
Case "TEXT", "MEMO":
FldValue = FldValue & ", '" & StrQuoteReplace(CrCell.Offset(RowCount, ColCount)) & "'"
Case Else:
FldValue = FldValue & ", " & CrCell.Offset(RowCount, ColCount)
End Select
End If
NextLoop:
ColCount = ColCount + 1
Wend
' Now inject into database
SqlTxt = "INSERT INTO " & tblName & "(form_id" & FldHdr & ") VALUES(" & FormID & FldValue & ");"
dbs.ExecuteSQL SqlTxt
' now get individual_id just inserted
idv_id = dbs.DMax("Id", tblName)
' For sub-tables
' reset header and values
FldHdr = ""
FldValue = ""
sub_tableName = ""
XXX:
While HdrCell.Offset(-2, ColCount) = "link"
If sub_tableName <> HdrCell.Offset(-1, ColCount) Then
If sub_tableName <> "" Then
'Commit SQL now with processing of row level using separator
FormatAndInject dbs, sub_tableName, idv_id, FldHdr, FldValue
' reset again...
FldHdr = ""
FldValue = ""
End If
sub_tableName = HdrCell.Offset(-1, ColCount)
End If
' since there maybe multiple value, we will have to parse them row by row
FldHdr = FldHdr & ", " & HdrCell.Offset(0, ColCount)
FldValue = FldValue & "[|]" & StrQuoteReplace(CrCell.Offset(RowCount, ColCount))
ColCount = ColCount + 1
Wend
'GoTo XXX
' now deal the last time for previous table
FormatAndInject dbs, sub_tableName, idv_id, FldHdr, FldValue
RowCount = RowCount + 1
Wend
End Sub
Private Sub FormatAndInject(dbs As clsDbConnection, TableName As String, ForeignKey As Long, HeaderRow As String, ValueRows As String)
' Break row value if needed
Dim SqlTxt As String, i As Long
Dim FldArr As Variant, VleArr1 As Variant, VleArr2 As Variant
HeaderRow = Mid(HeaderRow, 3)
ValueRows = Mid(ValueRows, 4)
FldArr = Split(HeaderRow, ", ")
If UBound(FldArr) = 0 Then
' only one field, separator is ";" - set as priority
If InStr(ValueRows, ";") > 0 Then
VleArr1 = Split(ValueRows, ";")
Else
VleArr1 = Split(ValueRows, ",")
End If
For i = 0 To UBound(VleArr1)
If VleArr1(i) <> "" Then
SqlTxt = "INSERT INTO " & TableName & "(individual_id, " & HeaderRow & ") VALUES(" & ForeignKey & ", '" & VleArr1(i) & "');"
dbs.ExecuteSQL SqlTxt
End If
Next
Else
FldArr = Split(ValueRows, "[|]")
VleArr1 = Split(IIf(Left(FldArr(0), 1) = vbLf, Mid(FldArr(0), 2), FldArr(0)), "," & vbLf)
VleArr2 = Split(IIf(Left(FldArr(1), 1) = vbLf, Mid(FldArr(1), 2), FldArr(1)), vbLf)
For i = 0 To UBound(VleArr1)
If VleArr1(i) <> "" Then
If i > UBound(VleArr2) Then
SqlTxt = "INSERT INTO " & TableName & "(individual_id, " & HeaderRow & ") VALUES(" & ForeignKey & ", '" & VleArr1(i) & "', '');"
Else
SqlTxt = "INSERT INTO " & TableName & "(individual_id, " & HeaderRow & ") VALUES(" & ForeignKey & ", '" & VleArr1(i) & "', '" & VleArr2(i) & "');"
End If
dbs.ExecuteSQL SqlTxt
End If
Next
End If
End Sub
Private Function GetSqlString() As String
Dim SqlTxt As String
Dim fldName As String, FldValue As String, HdrPtr As Range
Set HdrPtr = Range("tblFormInfor").Offset(0, 1)
While HdrPtr <> ""
If Not IsRangeValid(HdrPtr.Value) Then GoTo NextStep
' Just whether value is blank or not
If IsError(Range(HdrPtr)) Then GoTo NextStep
If Range(HdrPtr).Value <> "" Then
fldName = fldName & ", " & HdrPtr.Value
Else
If HdrPtr.Offset(-3) = 1 Then
MsgBox MSG("MSG_NO_BLANK"), vbInformation
GoTo CleanUp
End If
GoTo NextStep
End If
Select Case HdrPtr.Offset(-1)
Case "DATETIME":
FldValue = FldValue & ", #" & CDate(Range(HdrPtr).Value) & "#"
Case "TEXT", "MEMO":
FldValue = FldValue & ", '" & StrQuoteReplace(Range(HdrPtr)) & "'"
Case Else
FldValue = FldValue & ", " & Range(HdrPtr).Value
End Select
NextStep:
Set HdrPtr = HdrPtr.Offset(0, 1)
Wend
SqlTxt = "(" & Mid(fldName, 2) & ") VALUES(" & Mid(FldValue, 2) & ")"
CleanUp:
GetSqlString = SqlTxt
End Function
Sub Export2Excel(FilterStr As String)
'GetFiles SaveFormData
' this will open all for exporting
Dim SqlTxt As String, rs As ADODB.Recordset, dbs As New clsDbConnection
Dim wb As Workbook, wsh As Worksheet, ptrCell As Range
Dim StatusTxt As String
ShowOff
DoEvents
dbs.ConnectDatabase AppDatabase
SqlTxt = "Select FieldName,FieldCaption from tblFieldMap Where UseInExport=true AND TableName='tblFormInfor' ORDER BY ExcelFieldOrder ASC;"
Set rs = dbs.GetRecordSet(SqlTxt, True)
SqlTxt = ""
StatusTxt = MSG("MSG_SEND_DATA_TO_SHEET")
Set wb = Workbooks.Add
'copy me to the new workbook
ThisWorkbook.Sheets("household").Copy Before:=wb.Sheets(1)
Set wsh = wb.Sheets("household")
Set ptrCell = wsh.Cells(1)
While Not rs.EOF
ptrCell.Value = rs.Fields("FieldCaption")
SqlTxt = SqlTxt & "," & rs.Fields("FieldName")
Set ptrCell = ptrCell.Offset(0, 1)
rs.MoveNext
Wend
rs.Close
SqlTxt = "SELECT " & Mid(SqlTxt, 2) & " FROM tblFormInfor WHERE " & FilterStr & " AND txt_project <> '' AND txt_visit_date <> null;"
Application.StatusBar = Replace(StatusTxt, "%%", "[" & wsh.Name & "]")
Set rs = dbs.GetRecordSet(SqlTxt)
With wsh
.Cells(2, 1).CopyFromRecordset rs
.Range("W:W").NumberFormat = "General"
.Range("EI:EJ").NumberFormat = "General"
End With
' Show the sheeet now
wb.Names("rngFilter_hhld").RefersToRange.AutoFilter
wsh.UsedRange.WrapText = False
wsh.Visible = xlSheetVisible
' Now we have to load all individual data for these people
' It's a bit hard then?? quite some crosstab..
ThisWorkbook.Sheets("individual").Copy Before:=wb.Sheets(1)
Set wsh = wb.Sheets("individual")
Set ptrCell = wsh.Cells(2, 2)
rs.MoveFirst
While Not rs.EOF
Application.StatusBar = Replace(StatusTxt, "%%", "[" & wsh.Name & "]" & " Household IMS Code [" & rs.Fields("Form_ID") & "]!")
GetIndividualList rs.Fields("Form_ID"), dbs, ptrCell
rs.MoveNext
Wend
rs.Close
'===========
wb.Names("rngFilter_indv").RefersToRange.AutoFilter
wsh.UsedRange.WrapText = False
wsh.Visible = xlSheetVisible
wsh.Activate
' Delete other sheets
Application.DisplayAlerts = False
For Each wsh In wb.Sheets
If wsh.Name <> "household" And wsh.Name <> "individual" Then
Debug.Print wsh.Name
wsh.Delete
End If
Next
Application.DisplayAlerts = True
Set wb = Nothing
Set dbs = Nothing
Application.StatusBar = "Finished exporting..."
ShowOff True
End Sub
Private Sub GetIndividualList(FormID As Long, db As clsDbConnection, RowPtr As Range)
Dim Sql As String, RowCount As Long
Dim rs As New ADODB.Recordset
' First create this query....
Sql = "SELECT b.id, a.Form_ID AS Les_id, a.txt_project, a.txt_month_visit, a.txt_week_visit, " & _
"a.txt_visit_num_les_id, a.txt_IMS_ID, a.txt_IMS_ID_2, a.txt_house_owner, a.txt_village, " & _
"a.txt_commune, a.txt_staff_name, a.txt_visit_num, b.Member_Name, b.Mem_IMS, b.Mem_id, " & _
"b.Mem_gender, b.Mem_DOB, Month([Mem_DOB]) AS Mem_DOB_month, Year([Mem_DOB]) AS Mem_DOB_year, " & _
"DateDiff('yyyy',[Mem_DOB],Now()) AS Mem_age, b.Mem_DOB AS Mem_age_class, b.Mem_tel, " & _
"b.Mem_rel_hhld, b.Mem_rel_hhld_other, b.Edu, b.Edu_eval, b.Key_job, b.Key_job_other, " & _
"b.Min_job, b.Min_job_other, b.Job_status, b.Income_avrg, b.Insurance_support, " & _
"b.is_hhld_member, b.is_reallocate, b.Move_to, b.Move_reason, b.Move_reason_details, " & _
"b.skill_eval, b.link_type, b.no_link_reason, b.link_demand, b.link_dificulty " & _
"FROM tblFormInfor AS a INNER JOIN tblMembersInfor AS b ON a.Form_ID = b.form_id " & _
"WHERE a.form_id = " & FormID & ";"
' Load to Excel
RowCount = db.GetRecordSet("Select Count(*) " & _
"FROM tblFormInfor AS a INNER JOIN tblMembersInfor AS b ON a.Form_ID = b.form_id " & _
"WHERE a.form_id = " & FormID & ";", True).Fields(0)
Set rs = db.GetRecordSet(Sql)
RowPtr.CopyFromRecordset rs
Set RowPtr = RowPtr.Offset(RowCount)
rs.Close
End Sub
Sub RetrieveFields()
' This will do the cleaning of data before doing things, to avoid blank
Dim txtValue As Range, retVal As String, DataType As String, i As Long
Dim HdrCell As Range, rs As New ADODB.Recordset, db As New clsDbConnection
db.ConnectDatabase AppDatabase
Set rs = db.GetRecordSet("Select * from tblMembersInfor where form_id=0;", True)
Set HdrCell = Range("tbl_hhld_member_details").Offset(0, 1)
For i = 0 To rs.Fields.Count - 1
HdrCell.Offset(0, i) = rs.Fields(i).Name
HdrCell.Offset(-2, i) = ""
Select Case rs.Fields(i).Type
Case 202:
HdrCell.Offset(-1, i) = "TEXT"
HdrCell.Offset(-2, i) = rs.Fields(i).DefinedSize
Case 7:
HdrCell.Offset(-1, i) = "DATETIME"
Case 3:
HdrCell.Offset(-1, i) = "INTEGER"
Case 203:
HdrCell.Offset(-1, i) = "MEMO"
Case 4:
HdrCell.Offset(-1, i) = "SINGLE"
End Select
Next
rs.Close
Set db = Nothing
End Sub
Sub deleteChart()
Dim theChart As Chart
For Each theChart In ThisWorkbook.Charts
theChart.Delete
Next
End Sub
Sub TextMeNow()
SetSheetSize "individual"
SetSheetSize "household"
End Sub
Private Sub SetSheetSize(SheetName As String)
Dim tCell As Range, oCell As Range
Set tCell = ThisWorkbook.Sheets(SheetName).Cells(1)
Set oCell = ActiveWorkbook.Sheets(SheetName).Cells(1)
While oCell <> ""
tCell.ColumnWidth = oCell.ColumnWidth
Set tCell = tCell.Offset(0, 1)
Set oCell = oCell.Offset(0, 1)
Wend
End Sub